Java Android语句插入;后续呼叫失败

Java Android语句插入;后续呼叫失败,java,android,sqlite,prepared-statement,Java,Android,Sqlite,Prepared Statement,我正在尝试将行插入Android中的SQLite数据库。将记录插入数据库的调用如下所示:DataHelper.insertChild(context,child)。我的目标是将功能包装成静态调用的函数,这些函数处理所有的细节。首先让我和你分享我的代码 我通过静态方法来实现这一点: private static SQLiteDatabase prepareChildDatabase(Context context) { Log.d(TAG, "DB: prepareChildDatabas

我正在尝试将行插入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)";
所以现在发生的是,我第一次称之为“一切正常”。插入工作,数据在那里,我可以将DB从设备导出到我的SQLite浏览器。对insertChild(…)的后续调用会中断数据库。在SQLiteBrowser中打开不起作用,它不显示任何表或行,在文本编辑器中打开它会显示一些内容;我猜数据库已经损坏了。没有插入更多行,我无法读取。不会抛出任何错误

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

有人愿意帮我吗?我一直在写日志,寻找异常,尝试一些事情,但似乎什么都不起作用。我想我可能只是错过了一点细节。否则我就疯了

谢谢

迈克

更新

我把注意力转向了线程,因为这个问题不会在我的模拟器上重现。查看以下链接:


您应该在需要时随时打开连接。或者在关闭它之前先打开它,然后再执行所有插入操作。

首先……当您使用DB实例、游标实例或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();
        }
    }

如果在进程中间抛出异常,您将关闭DB。< /P> 删除此最终版本

final long id = insertStmt.executeInsert();

为了更好地进行调试,请在try/finally中添加一个陷阱,这样您将更好地了解正在进行的操作。

我正在测试的设备似乎在权限和写入数据库文件方面存在问题。问题实际上是最初创建数据库,插入行,然后锁定它。随后的呼叫会破坏它


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

是的,每次插入时,我都会调用getWritableDatabase(),根据文档,它应该“创建和/或打开一个用于读写的数据库”。这些插入很少被调用,所以每次调用我都可以打开和关闭数据库。看看我的函数prepareDatabase(…)。它在函数开始时被调用,并将打开一个连接。prepareChildDatabase和prepareDatabase是相同的吗?在我接近实现DataHelper对象之前,我一直没有使用try/catch/finally最佳实践。既然这个问题没有解决,它也帮不了我。我很好奇为什么我应该放弃决赛。该建议不符合Java最佳实践。它在executeInsert()的输出中递增。