我一直在努力完善可工作的 SQLite 数据库还原。更具体地说,当数据库损坏时(我一直在使用其中包含SQL的文件,并将其复制到数据库文件而不是数据库副本)。

我可以通过使用SQL查看 sqlite_master 来在没有处理程序的情况下进行处理(没有表可以检测到损坏)。

当我在研究技术时遇到DatabaseErrorHanlder时,我以为我会涉猎 DatabaseErorHandler

我已经到了触发DataBaseErrorHandler的阶段(调用了处理程序内的日志(由于第二次尝试读取两次)。但是,与使用null而不是处理程序相比,我收到的错误报告更多,并且应用程序崩溃(好像让处理程序关闭了SQLite的自动功能一样,我相信删除了损坏的文件,因此对处理程序的任何调用都会重新创建它) 。崩溃不是一个问题,因为SQLite显然已经设法解决了这种损坏,但是似乎处理程序停止了它所做的工作。)

在没有处理程序的情况下运行会导致以下消息(首先由应用编写为路标):

11-03 16:36:13.414 10959-10959/? I/mjt.shopper: Thu Nov 03 16:36:13 AEDT 2016 Activity=dataBaseIntegrityCheck Method=MainDataHandling MSG=restore Database Integrity Check - IC Database created
11-03 16:36:13.415 10959-10959/? E/SQLiteLog: (26) file is encrypted or is not a database
11-03 16:36:13.416 10959-10959/? E/DefaultDatabaseErrorHandler: Corruption reported by sqlite on database: /data/data/mjt.shopper/databases/ICShopper
11-03 16:36:13.416 10959-10959/? E/DefaultDatabaseErrorHandler: deleting the database file: /data/data/mjt.shopper/databases/ICShopper

与我得到的处理程序一起运行(相同的路标+由处理程序发布的路标):-
11-03 16:58:23.923 12265-12265/? I/mjt.shopper: Thu Nov 03 16:58:23 AEDT 2016 Activity=dataBaseIntegrityCheck Method=MainDataHandling MSG=restore Database Integrity Check - IC Database created
11-03 16:58:23.925 12265-12265/? E/SQLiteLog: (26) file is encrypted or is not a database
11-03 16:58:23.925 12265-12265/? I/mjt.shopper: Thu Nov 03 16:58:23 AEDT 2016 Activity=MainDataHandling Method=dataBaseIntegrityCheck MSG=DB onCorruption error handler invoked
11-03 16:58:23.925 12265-12265/? E/SQLiteLog: (26) file is encrypted or is not a database
11-03 16:58:23.927 12265-12265/? E/SQLiteDatabase: Failed to open database '/data/data/mjt.shopper/databases/ICShopper'.
                                                   android.database.sqlite.SQLiteDatabaseCorruptException: file is encrypted or is not a database (code 26): , while compiling: PRAGMA journal_mode
.............
11-03 16:58:23.928 12265-12265/? E/SQLiteOpenHelper: Couldn't open ICShopper for writing (will try read-only):
                                                     android.database.sqlite.SQLiteDatabaseCorruptException: file is encrypted or is not a database (code 26): , while compiling: PRAGMA journal_mode
'''''''''''''
11-03 16:58:23.929 12265-12265/? E/SQLiteLog: (26) statement aborts at 1: [PRAGMA user_version;] file is encrypted or is not a database
11-03 16:58:23.930 12265-12265/? I/mjt.shopper: Thu Nov 03 16:58:23 AEDT 2016 Activity=MainDataHandling Method=dataBaseIntegrityCheck MSG=DB onCorruption error handler invoked
11-03 16:58:23.934 12265-12265/? D/AndroidRuntime: Shutting down VM
11-03 16:58:23.934 12265-12265/? E/AndroidRuntime: FATAL EXCEPTION: main
                                                   Process: mjt.shopper, PID: 12265
                                                   android.database.sqlite.SQLiteDatabaseCorruptException: file is encrypted or is not a database (code 26)

DatabaseHelper代码是:-
public class IntegrityCheckDBHelper extends SQLiteOpenHelper implements DatabaseErrorHandler{

    public static final String DATABASE_NAME = "IC"+ShopperDBHelper.DATABASE_NAME;
    public static final int DATABASE_CORRUPTED = 1;
    private static int databasestate = 0;
    private Context context;

    public IntegrityCheckDBHelper(Context context,
                                  String name,
                                  SQLiteDatabase.CursorFactory factory,
                                  int version, DatabaseErrorHandler errorHandler) {
        super(context, DATABASE_NAME,factory,1,errorHandler);
        this.context = context;

    };

    public void onCreate(SQLiteDatabase db) {};
    public void onUpgrade(SQLiteDatabase db, int oldversion, int newversion) {};
    public void onCorruption(SQLiteDatabase db) {
    }
    public boolean checkDB() {
        SQLiteDatabase icdb = this.getReadableDatabase();
        String icsqlstr = " PRAGMA quick_check";
        Cursor iccsr;
        iccsr = icdb.rawQuery(icsqlstr,null);
        return false;
    }
    public static void setDatabaseCorrupted() {
        databasestate = DATABASE_CORRUPTED;
    }
    public boolean isDatabaseCouurpted() {
        if(databasestate != 0) return false;
        return true;
    }
}

注意!此帮助程序专门用于检查还原文件是否可以被用户使用(因此,无需onCreate/onUpgrade即可执行任何操作我认为)。

这是相关代码,即 dataBaseIntegrityCheck 方法(即从要还原的备份中创建数据库文件以检查备份是否创建了有效的数据库):-
private boolean dataBaseIntegrityCheck() {

        final String THIS_METHOD = "dataBaseIntegrityCheck";
        String sqlstr_mstr = "SELECT name FROM sqlite_master WHERE type = 'table' AND name!='android_metadata' ORDER by name;";
        Cursor iccsr;
        boolean rv = true;
        DatabaseErrorHandler myerrorhandler = new DatabaseErrorHandler() {
            @Override
            public void onCorruption(SQLiteDatabase sqLiteDatabase) {
                mjtUtils.logMsg(mjtUtils.LOG_INFORMATIONMSG,"DB onCorruption error handler invoked",THIS_ACTIVITY,THIS_METHOD,true);
                dbcorrupted = true;
            }
        };
        mjtUtils.logMsg(mjtUtils.LOG_INFORMATIONMSG,"Restore Databae Integrity Check - Starting",THIS_METHOD,THIS_ACTIVITY,true);
        try {
            FileInputStream bkp = new FileInputStream(backupfilename);
            OutputStream ic = new FileOutputStream(icdbfilename);
            while ((copylength = bkp.read(buffer)) > 0) {
                ic.write(buffer, 0, copylength);
            }
            ic.close();
            bkp.close();

            mjtUtils.logMsg(mjtUtils.LOG_INFORMATIONMSG,"restore Database Integrity Check - IC Database created",THIS_METHOD,THIS_ACTIVITY,true);

            //Note SQLite will actually check for corruption and if so delete the file
            IntegrityCheckDBHelper icdbh = new IntegrityCheckDBHelper(this,null,null,1,myerrorhandler);

            //>>>>>>>>>>>>> Errors all point here (the getReadableDatabase)
            SQLiteDatabase icdb = icdbh.getReadableDatabase();

            if(dbcorrupted) {
                mjtUtils.logMsg(mjtUtils.LOG_INFORMATIONMSG,"DB corrupted",THIS_ACTIVITY,THIS_METHOD,true);
                return false;
            }

            //Check to see if there are any tables, if wrong file type shouldn't be any
            iccsr = icdb.rawQuery(sqlstr_mstr,null);
            if(iccsr.getCount() < 1) {
                errlist.add("Integrity Check extract from sqlite_master returned nothing - Propsoed file is corrupt or not a database file.");
                rv = false;
            }
            iccsr.close();
            icdb.close();

        } catch (IOException e) {
            e.printStackTrace();
            errlist.add("Integrity Check Failed Error Message was " + e.getMessage());
        }

        if(!rv) {
            // AlertDialog removed.
        }
        return rv;
    }

要重申一下,问题主要是关于DatabaseErrorHandler以及我可以,不能和/或应该做什么。

我发现的文档以及我看过的许多帖子似乎都没有帮助。

最佳答案

SQLiteDatabase.open()中的相关代码如下所示:

        try {
            openInner();
        } catch (SQLiteDatabaseCorruptException ex) {
            onCorruption();
            openInner();
        }

因此,您的onCorruption()处理程序必须在数据库返回之前对其进行还原;这不能推迟到以后。

如果您实际上不想还原要打开的数据库,则使用onCorrupt()处理程序没有任何意义。

10-08 16:41