19

我第一次使用 SQLite,并试图学习它的异常处理,所以我在我的测试应用程序中强制插入错误。发生异常,我看到它已写入 Eclipse LogCat 输出窗口。但是它不会被代码捕获。我在这里看到了关于确保使用正确的异常类型的其他问题,并认为我做对了。知道我错过了什么吗?

在我的主要活动中的以下语句中,myTable是一个扩展我自己AbstractDbAdapter的类(它有一个DatabaseHelper扩展类SQLiteOpenHelper)。

try {
    myTable.create("dupkey");
}
catch (android.database.sqlite.SQLiteConstraintException e) {
    Log.e(TAG, "SQLiteConstraintException:" + e.getMessage());
}
catch (android.database.sqlite.SQLiteException e) {
    Log.e(TAG, "SQLiteException:" + e.getMessage());
} 
catch (Exception e) {
    Log.e(TAG, "Exception:" + e.getMessage());
}

示例堆栈跟踪:

Error inserting id="dupkey" last_seen_ts=1360624732 first_seen_ts=1360624732 android.database.sqlite.SQLiteConstraintException: error code 19: constraint failed
  at android.database.sqlite.SQLiteStatement.native_execute(Native Method)
  at android.database.sqlite.SQLiteStatement.execute(SQLiteStatement.java:61)
  at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1582)
  at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1426)
  at com.myCompany.testApp.myTable_DbAdapter.create(myTable_DbAdapter.java:51)

myTableAbstractDbAdapter

公共类 myTable_DbAdapter 扩展 AbstractDbAdapter {

    私有静态最终字符串 DATABASE_TABLE = "myTable";

    // 列名 -- ContentValues() 的键
    公共静态最终字符串 KEY_ID = "id";
    公共静态最终字符串 KEY_FIRST_SEEN = "first_seen_ts";
    公共静态最终字符串 KEY_LAST_SEEN = "last_seen_ts";

    公共 myTable_DbAdapter(上下文 ctx){
        超级(ctx);
    }

    公共长创建(字符串ID){
        long firstSeen = System.currentTimeMillis() / 1000; // SQLite 时间戳以秒为单位

        内容值参数 = 新的内容值();
        args.put(KEY_ID, id);
        args.put(KEY_FIRST_SEEN, firstSeen);
        args.put(KEY_LAST_SEEN, firstSeen); // 默认为 firstSeen 用于新条目

        返回 mDb.insert(DATABASE_TABLE, null, args);
    }
}

公共抽象类 AbstractDbAdapter {

    protected static final String TAG = "AbstractDbAdapter";

    受保护的 DatabaseHelper mDbHelper = null;
    受保护的 SQLiteDatabase mDb = null;

    受保护的静态最终字符串 TABLE_CREATE_MYTABLE =
        "创建表我的表(" +
        " id text 主键不为空" +
        ", first_seen_ts 整数不为空" +
        ", last_seen_ts 整数不为空" +
        ");";

    protected static final String DATABASE_NAME = "myDB";
    受保护的静态最终 int DATABASE_VERSION = 1;

    受保护的最终上下文 mCtx;

    受保护的静态类 DatabaseHelper 扩展 SQLiteOpenHelper {

        DatabaseHelper(上下文上下文){
            超级(上下文,DATABASE_NAME,空,DATABASE_VERSION);
        }

        @覆盖
        公共无效onCreate(SQLiteDatabase db){
            // 注意:SQLite 每个表需要一个 execSQL
            db.execSQL(TABLE_CREATE_MYTABLE);
        }

        @覆盖
        公共无效 onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion){
            Log.w(TAG, "将数据库从版本" + oldVersion + "升级到" + newVersion + ",破坏现有数据。");
            db.execSQL("如果存在 myTable 则删除表");
            onCreate(db);
        }
    }

    公共 AbstractDbAdapter(上下文 ctx){
        这个.mCtx = ctx;
    }

    公共 AbstractDbAdapter open() 抛出 SQLException {
        mDbHelper = 新的数据库助手(mCtx);
        mDb = mDbHelper.getWritableDatabase();
        返回这个;
    }

    公共无效关闭(){
        如果(mDb!= null){
            mDb.close();
            mDb = 空;
        }
        如果(mDbHelper!= null){
            mDbHelper.close();
            mDbHelper = null;
        }
    }

}
4

2 回答 2

31

我在这里找到了答案:SQLiteConstraintException 未捕获

SQLiteDatabase.insert() 方法不会引发异常。哦!

对于像我这样的其他 SQLite 新手,如果您想在插入数据库时​​捕获异常,请使用 SQLite.insertOrThrow() 方法。它会抛出一个异常,然后您可以捕获并处理该异常。

于 2013-02-12T01:12:20.110 回答
1

虽然不是 100% 与该问题相关,但我在使用 Room 时遇到了类似的问题,Google 为我的搜索返回了这个问题。在 Room 的情况下,似乎没有抛出可捕获的异常,并且 insertOrThrow() 不存在。在审查https://developer.android.com/reference/kotlin/androidx/room/OnConflictStrategy#ABORT:kotlin.Int时,许多选项都被贬值了,但我在这里选择了 OnConflictStrategy.IGNORE 因为这将返回 -1 如果有一个问题。

干杯。

于 2020-10-15T20:20:02.297 回答