Java Android语句插入;后续呼叫失败
我正在尝试将行插入Android中的SQLite数据库。将记录插入数据库的调用如下所示:DataHelper.insertChild(context,child)。我的目标是将功能包装成静态调用的函数,这些函数处理所有的细节。首先让我和你分享我的代码 我通过静态方法来实现这一点: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
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()的输出中递增。