为什么我的安卓SQLite数据库突然损坏了?

5

突然间,我的应用程序使用的数据库似乎已经损坏了。 我没有改变数据库的结构,但今天我在设备上重新部署了几次应用程序。

它抛出以下异常。

E/Database(14281): CREATE TABLE android_metadata failed err=26 ..
E/Database(14281): Failed to setLocale() when constructing, closing the database
E/Database(14281): android.database.sqlite.SQLiteException: file is encrypted or is not  a database
E/Database(14281):  at android.database.sqlite.SQLiteDatabase.native_setLocale(Native  Method)
E/Database(14281):  at android.database.sqlite.SQLiteDatabase.setLocale(SQLiteDatabase.java:1848)
E/Database(14281):  at android.database.sqlite.SQLiteDatabase.<init>(SQLiteDatabase.java:1798)
E/Database(14281):  at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:798)
E/Database(14281):  at   android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:857)
E/Database(14281):  at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:850)
E/Database(14281):  at android.app.ApplicationContext.openOrCreateDatabase(ApplicationContext.java:539)
E/Database(14281):  at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:193)
E/Database(14281):  at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:98)
E/Database(14281):  at com.ecs.android.gps.storage.DBAdapter.open(DBAdapter.java:75)

使用SQLLiteOpenHelper类来初始化数据库。

public DBAdapter(Context ctx) 
{
    this.context = ctx;
    DBHelper = new DatabaseHelper(context);
}

private static class DatabaseHelper extends SQLiteOpenHelper 
{
    DatabaseHelper(Context context) 
    {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) 
    {
        db.execSQL(DATABASE_CREATE);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, 
    int newVersion) 
    {
        Log.w(TAG, "Upgrading database from version " + oldVersion 
                + " to "
                + newVersion + ", which will destroy all old data");
        db.execSQL("DROP TABLE IF EXISTS location_history");
        onCreate(db);
    }
}  
  • 我基本上在每次操作时都会打开/关闭数据库和游标。
  • 一些文章表明这是正确的方法,但对于Android应用程序来说,保持数据库连接始终开启是否更有意义?
  • 我可以想象每次打开/关闭它需要更多资源。
  • 有多个活动和服务访问数据库。(潜在地同时)
  • 我从未在日志中看到异常。

您有什么想法可能导致了这个问题,如何恢复它,并如何防止将来出现这种情况? 我有印象这个异常是由于一些并发问题引起的(多个线程尝试打开/关闭或读写数据库)。我不知道 SQLite 数据库在多线程访问、锁定等方面与普通数据库(MySQL-Oracle)相比有多强大......


你是否考虑过使用数据提供程序来在多个活动之间共享数据? - Emile
这是我的待办事项清单上的一项,据我所知,它可能是一个选项,因为它可以为您处理很多基础工作,但是我只有一个表格需要读取和写入。我也没有将数据暴露给其他应用程序的意图。我只想知道它是如何被损坏的,以及如何避免它(仍然使用std SQLiteDatabase和SQLiteOpenHelper类)。 - ddewaele
除非您已经修复了它,否则我建议进一步调查rosstheboss的答案。您提到有服务和活动访问数据库。鉴于两个活动从未真正同时处于活动状态,您可以假设它们是安全的。但是,您提到的服务可能会与Activity同时运行。我不是Java专家,但我想象有一些方法可以帮助锁定/检查数据库上的锁定。例如,是否已打开或锁定/解锁数据库。这将使您避免冲突,并至少捕获错误。 - Emile
刚刚遇到了同样的错误,但是是在我的 Google 联系人内容提供程序数据库中。删除联系人数据后问题得到解决。正如建议的那样,我想问题可能是同时访问您的数据库导致磁盘上的数据损坏。 - Emile
2个回答

0
Ae sql lite DB文件不是以文本可读格式存在的吗?你不能解析DB文件来重建它吗?另外,locale属性不是设置在元数据表上的吗?如果是这样的话,删除该表并手动创建它可能会恢复您的DB。

实现重建数据库文件的逻辑是我不想在这里实现的 :) android_metadata确实是自动创建的,但是从堆栈跟踪来看,我的感觉是Android已经决定DB已经损坏,并在那时删除数据库并重新创建它(我认为这是标准的Android SQLite行为)。就是在那个重新创建的过程中出了问题。我正在努力找出导致损坏的原因。 - ddewaele
你能重复这个问题吗?每次你重新安装应用程序。 - Emile
评论中提到的重新创建并不是指安装应用程序时的初始创建数据库,而是当Android检测到损坏的数据库文件时发生的重新创建。这很难复制...我可以让应用程序运行数天,突然弹出。下一次可能会在几个小时后弹出。 - ddewaele

0

可能以某种非法状态离开了数据库,尽管通常会被标记并且一切都正常进行。


我基本上在每个操作中打开/关闭数据库和游标。有多个活动和服务访问数据库。然而,我从未在日志中看到异常。 - ddewaele
这里的大问题是没有简单的方法来恢复。你基本上需要卸载应用程序(导致它删除数据库)并重新安装以解除阻塞状态。 - ddewaele
你可以尝试一下。前往SDK工具文件夹并运行shell工具adb,然后使用sqlite3来浏览表格。如果这不起作用,你可能可以将其从此处复制到本地计算机,并使用其他工具进行恢复。 - Emile
这是一个将安装在多个手机上的应用程序,因此手动修复不是一个选项。数据库文件不应该损坏(只要应用程序正常运行且未被任务管理器或其他东西不断杀死)。 - ddewaele
重新阅读了您最初的帖子,我仍然无法给出关于为什么会出现“损坏”的具体答案。如果您认为这可能是线程问题,最好尝试通过线程安全队列访问所有的数据库调用。我通常倾向于每个操作打开和关闭一个数据库,这似乎不会增加太多开销,并有助于确保它始终处于良好状态。 - rosstheboss

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接