gpt4 book ai didi

android - SQLite 数据库、多线程、Android 上的锁和帐户同步

转载 作者:IT王子 更新时间:2023-10-29 06:24:33 29 4
gpt4 key购买 nike

我正在尝试获得一种模式,该模式不会因多线程访问我的 sqlite 数据库而失败。此外,让我发疯的是我无法重现该问题。

我有一个使用数据库的应用程序,还有 Android 帐户和 Android 同步来同步我的应用程序的数据。我的猜测是,当两者同时发生时,它会崩溃。我收到很多错误,例如:

 * android.database.sqlite.SQLiteDatabaseLockedException: database is locked
* android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5)
* android.database.sqlite.SQLiteDatabaseLockedException: error code 5: database is locked
* android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5): , while compiling: PRAGMA journal_mode
* android.database.sqlite.SQLiteDiskIOException: disk I/O error (code 778)
* android.database.sqlite.SQLiteException: Failed to change locale for db '/data/data/net.bicou.redmine/databases/redmine.db' to 'en_US'. \n Caused by: android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5)

也许并非所有这些都与同一个根本原因有关,但我有点迷路了。

我有的是:

  • 一个抽象基类,DbAdapter,由想要管理单个表的子类扩展
  • 一个管理 SQLite 数据库的类,称为 DbManager,其中包含一个 Lock

现在用户有一个不是单例的 DbManager 版本。我打算使 DbManager 成为单例,以便所有线程共享同一个对象。这应该不是问题,因为据我所知/所见,后台同步和应用程序共享相同的进程。

这里是类(只有相关部分):

public abstract class DbAdapter {
Context mContext;
protected DbManager mDbManager;
SQLiteDatabase mDb;

public static final String KEY_ROWID = "_id";

public DbAdapter(final Context ctx) {
mContext = ctx;
}

public DbAdapter(final DbAdapter other) {
mContext = other.mContext;
mDb = other.mDb;
mDbManager = other.mDbManager; // removed with singleton version
}

public synchronized DbAdapter open() throws SQLException {
if (mDb != null) {
return this;
}

mDbManager = new DbManager(mContext); // currently in production
mDbManager = DbManager.instance(mContext); // currently investigating this singleton solution
try {
mDb = mDbManager.getWritableDatabase();
} catch (final SQLException e) {
L.e("Unable to open DB, trying again in 1 second", e);
try {
Thread.sleep(1000);
} catch (final InterruptedException e1) {
L.e("Could not wait 1 second " + e1);
}
mDb = mDbManager.getWritableDatabase();// This may crash
}

return this;
}

public synchronized void close() {
mDbManager.close();
mDbManager = null;
mDb = null;
}
}

需要处理数据库表的类会继承DbAdapter,实现selectinsertdelete等方法

这是数据库管理器:

public class DbManager extends SQLiteOpenHelper {
private static final String DB_FILE = "db";
private static final int DB_VERSION = 15;
Context mContext;
Lock mLock = new ReentrantLock();

// Currently in prod
public DbManager(final Context context) {
super(context, DB_FILE, null, DB_VERSION);
mContext = context;
}

// singleton version will make this constructor private and add:
private static DbManager mInstance;
public static synchronized DbManager instance(Context context) {
if (instance == null) {
instance = new DbManager(context);
}
return instance;
}

@Override
public SQLiteDatabase getWritableDatabase() {
mLock.lock();
return super.getWritableDatabase();
}

@Override
public void close() {
super.close();
mLock.unlock();
}

@Override
public void onCreate(final SQLiteDatabase db) {
// ...
}

@Override
public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
// ...
}

private void createTables(final SQLiteDatabase db, final String[] statements) {
for (final String sql : statements) {
try {
db.execSQL(sql);
} catch (final Exception e) {
L.e("Unable to create table: " + sql, e);
}
}
}
}

好的,现在,问题。

  1. 我的锁是否正确实现?我对此很陌生,我不知道 ReentrantLock 是否是一个不错的选择,以及我是否在正确的时刻锁定/解锁
  2. 我的同步方法是否正确实现?我的意思是,我在不想被并发线程中断的方法周围放置了 synchronized 关键字。这是正确的吗?你能就我的synchronized 使用提出建议吗?
  3. 如何重现该问题?我创建了一个测试,它使用 3 个线程对数据库进行并发读/写访问,并使用一些 Thread.sleep 来确保每个线程的数据库打开/关闭重叠,但它不会不会崩溃。这真的很困扰我,我认为没有很多人遇到这个问题,所以我不知道如何重现。
  4. 我的 DbAdapter + DbManager 技术选择是个好主意吗?有更好的模式吗?
  5. DbManager 成为单例是个好主意吗?

最佳答案

对于多线程访问,建议使用单例模式。

这样,对同一数据库的连续调用将被无缝序列化。

但是,在插入时出现一些 NullPointerException 并非不可能。因此,要扩展您的“Thread.sleep”逻辑,您可以使用以下代码:

@Override
public SQLiteDatabase getWritableDatabase() {
while (true) {
try {
return super.getWritableDatabase();
} catch (SQLiteDatabaseLockedException e) {
System.err.println(e);
}

try {
Thread.sleep(500);
} catch (InterruptedException e) {
System.err.println(e);
}
}
}

关于android - SQLite 数据库、多线程、Android 上的锁和帐户同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17718063/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com