Android SQLiteStatement Insert;后续调用失败

时间:2011-03-28 21:16:51

标签: java android sqlite prepared-statement

我正在尝试在Android中的SQLite数据库中插入行。将记录插入我的数据库的调用如下所示:DataHelper.insertChild(context,child)。我的目标是将功能包装到静态调用的函数中,以处理所有细节。首先让我与您分享我的代码。

我是通过静态方法做到的:

private static SQLiteDatabase prepareChildDatabase(Context context) {
    Log.d(TAG, "DB: prepareChildDatabase");
    OpenHelper openHelper = new OpenHelper(context);
    return openHelper.getWritableDatabase();
}

然后我做插入:

    public static long insertChild(Context context, Child child) {
    Log.d(TAG, "DB: insertChild");

    SQLiteDatabase db = prepareChildDatabase(context);
    SQLiteStatement insertStmt = db.compileStatement(INSERT);
    insertStmt.bindLong(1, child.getBirthday().getTime());

    // These are optional
    if(child.getName() != null) {
        insertStmt.bindString(2, child.getName());
    } else {
        insertStmt.bindNull(2);
    }

    if(child.getPhoto() != null) {
        String photoUri = child.getPhoto().toString();
        insertStmt.bindString(3, photoUri);
    } else {
        insertStmt.bindNull(3);
    }

    final long id = insertStmt.executeInsert();

    // insertStmt.clearBindings(); // Not sure this is necessary
    insertStmt.close();
    db.close();

    return id;
}

对于参考,我的OpenHelper就在这里:

    private static class OpenHelper extends SQLiteOpenHelper {

    OpenHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        Log.d(TAG, "DB: OpenHelper: onCreate: " + CREATE_CHILDREN_TABLE);
        db.execSQL(CREATE_CHILDREN_TABLE);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
        onCreate(db);
    }
}

最后,变量,语句和表:

private static final String TABLE_NAME = "children";
private static final String COL_NAME = "name";
private static final String COL_BDAY = "birthday";
private static final String COL_PHOTO = "photo";

private static final String INSERT = "insert into " 
    + TABLE_NAME + " (" 
        + COL_BDAY + ", "
        + COL_NAME + ", " 
        + COL_PHOTO + ") values (?, ?, ?)";

private static final String UPDATE = "update " 
    + TABLE_NAME + "set "
        + COL_BDAY + " = ?, "
        + COL_NAME + " = ?, "
        + COL_PHOTO + " = ?) WHERE "
        + BaseColumns._ID + " = ?";

private static final String CREATE_CHILDREN_TABLE = 
    "CREATE TABLE " + TABLE_NAME + " ("
        + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
        + COL_BDAY + " INTEGER NOT NULL, "
        + COL_NAME + " TEXT NULL, "
        + COL_PHOTO + " TEXT NULL)";

所以发生的事情是,我第一次称之为一切正常。插入工作,数据存在,我可以将数据库从设备导出到我的SQLite浏览器。对insertChild(...)的后续调用会破坏DB。打开不起作用,SQLiteBrowser不显示任何表或行,并在文本编辑器中打开它显示一些东西;我的猜测是数据库已损坏。没有更多的行被插入,我无法读取它。 不会抛出任何错误。

我猜这里发生了两件事之一。首先,我的句柄没有正确打开/关闭,某些地方的引用被随后的调用搞砸了。其次,我对准备好的陈述的理解是错误的。问题是我看代码,看起来很好。打开数据库,绑定到预准备语句,执行,关闭语句,关闭数据库。

有谁愿意帮我解决这个问题?我一直在记录,寻找异常,并尝试一些东西,但似乎没有任何工作。我想我可能只是错过了一些细节。那或我疯了。

谢谢,

麦克

更新

我已将注意力转向线程,因为问题不会在我的模拟器上重现。看看这些链接:

http://www.kagii.com/journal/2010/9/10/android-sqlite-locking.html

android sqlite application is being forcefully closed on device

What are the best practices for SQLite on Android?

3 个答案:

答案 0 :(得分:0)

您应该始终打开连接。或者在关闭它之前打开所有插入之前打开它。

答案 1 :(得分:0)

首先....当您使用数据库实例或游标实例或Steatment实例(或者最后需要关闭的任何内容)时,请使用以下语法;

    SQLiteOpenHelper db;
    try{
        db = myDB.open();//open the database here
        //do whatever you want with the DB instance
    }finally{
        if(db != null){
            db.close();
        }
    }

如果在流程中间抛出异常,您将关闭数据库。

删除此最终

final long id = insertStmt.executeInsert();

为了更好地调试,在try / finally中加入一个catch,你会看到更好的结果。

答案 2 :(得分:0)

我正在测试的设备似乎存在权限问题和编写数据库文件。问题实际上是DB最初创建,插入行,然后它被锁定。后续调用会破坏它。

这可能是设备生根的结果。或者可能因为包UID已更改。