从不同线程同时访问 SQLite 数据库
Access SQLite database simultaneously from different threads
这是我的问题。我的应用程序启动了多个线程,每个线程用于要更新的特定对象。对象的更新发生在对单个数据库的查询中。只有一个数据库和一个 OpenHelper。我的应用程序的行为表明对数据库的调用不是同时进行的,正如我所希望的那样。如何同时从不同线程访问同一个数据库?如果每个对象的数据在不同的表中,将数据库拆分为多个数据库更有效,每个对象一个?
public class SomethingToBeUpdated implements Runnable {
private SQLiteDatabase db;
@Override
public void run() {
db.rawQuery( ... bla bla
}
}
public class MainActivity extends Activity {
private SomethingToBeUpdated[] list = bla bla...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
for( SomethingToBeUpdated x : list ) {
new Thread(x).start();
}
}
}
为了在各种线程中访问数据库,您需要有一个数据库管理器来保存数据库的对象 class 并将其传递给需要它的任何线程。在 android 中,您不能在具有不同对象的多个线程中同时访问数据库。它可能会阻止您的 UI(我几天前遇到的问题)。
因此,为了克服这个问题,您可以使用我使用的数据库管理器,其定义如下:
public class DatabaseManager {
private AtomicInteger mOpenCounter = new AtomicInteger();
private static DatabaseManager instance;
private static SQLiteOpenHelper mDatabaseHelper;
private SQLiteDatabase mDatabase;
public static synchronized void initializeInstance(SQLiteOpenHelper helper) {
if (instance == null) {
instance = new DatabaseManager();
mDatabaseHelper = helper;
}
}
public static synchronized DatabaseManager getInstance() {
if (instance == null) {
throw new IllegalStateException(DatabaseManager.class.getSimpleName() +
" is not initialized, call initializeInstance(..) method first.");
}
return instance;
}
public synchronized SQLiteDatabase openDatabase() {
if(mOpenCounter.incrementAndGet() == 1) {
mDatabase = mDatabaseHelper.getWritableDatabase();
}
return mDatabase;
}
public synchronized void closeDatabase() {
if(mOpenCounter.decrementAndGet() == 0) {
mDatabase.close();
}
}
}
然后像这样初始化一次:
DatabaseManager.initializeInstance(new ChatSQL(c));
然后您可以使用以下语法在任意位置获取数据库对象:
SQLiteDatabase db = DatabaseManager.getInstance().openDatabase(); //in your methods which are querying the database
使用此方法,您的数据库现在是线程安全的。希望这有帮助。
If the data for each object are in different tables is more efficient to split the database in several databases, one for each object?
不,效率不高。它有很多开销来定义、访问、创建对象和查询不同的数据库。如果你想加入表格怎么办?你就是做不到。
这是我的问题。我的应用程序启动了多个线程,每个线程用于要更新的特定对象。对象的更新发生在对单个数据库的查询中。只有一个数据库和一个 OpenHelper。我的应用程序的行为表明对数据库的调用不是同时进行的,正如我所希望的那样。如何同时从不同线程访问同一个数据库?如果每个对象的数据在不同的表中,将数据库拆分为多个数据库更有效,每个对象一个?
public class SomethingToBeUpdated implements Runnable {
private SQLiteDatabase db;
@Override
public void run() {
db.rawQuery( ... bla bla
}
}
public class MainActivity extends Activity {
private SomethingToBeUpdated[] list = bla bla...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
for( SomethingToBeUpdated x : list ) {
new Thread(x).start();
}
}
}
为了在各种线程中访问数据库,您需要有一个数据库管理器来保存数据库的对象 class 并将其传递给需要它的任何线程。在 android 中,您不能在具有不同对象的多个线程中同时访问数据库。它可能会阻止您的 UI(我几天前遇到的问题)。
因此,为了克服这个问题,您可以使用我使用的数据库管理器,其定义如下:
public class DatabaseManager {
private AtomicInteger mOpenCounter = new AtomicInteger();
private static DatabaseManager instance;
private static SQLiteOpenHelper mDatabaseHelper;
private SQLiteDatabase mDatabase;
public static synchronized void initializeInstance(SQLiteOpenHelper helper) {
if (instance == null) {
instance = new DatabaseManager();
mDatabaseHelper = helper;
}
}
public static synchronized DatabaseManager getInstance() {
if (instance == null) {
throw new IllegalStateException(DatabaseManager.class.getSimpleName() +
" is not initialized, call initializeInstance(..) method first.");
}
return instance;
}
public synchronized SQLiteDatabase openDatabase() {
if(mOpenCounter.incrementAndGet() == 1) {
mDatabase = mDatabaseHelper.getWritableDatabase();
}
return mDatabase;
}
public synchronized void closeDatabase() {
if(mOpenCounter.decrementAndGet() == 0) {
mDatabase.close();
}
}
}
然后像这样初始化一次:
DatabaseManager.initializeInstance(new ChatSQL(c));
然后您可以使用以下语法在任意位置获取数据库对象:
SQLiteDatabase db = DatabaseManager.getInstance().openDatabase(); //in your methods which are querying the database
使用此方法,您的数据库现在是线程安全的。希望这有帮助。
If the data for each object are in different tables is more efficient to split the database in several databases, one for each object?
不,效率不高。它有很多开销来定义、访问、创建对象和查询不同的数据库。如果你想加入表格怎么办?你就是做不到。