问题
I'm downloading an SQLite database file from a server to the Android device of the user. After the download, I insert or replace some tables in the local database using the downloaded database. I use ORMLite 4.47 for this.
First I attach the database files to the DatabaseConnection:
DatabaseConnection con = null;
con = conSrc.getReadWriteConnection();
con.executeStatement("attach database '" + localDatabase.getAbsolutePath() + "' as '" + localDb + "'", DatabaseConnection.DEFAULT_RESULT_FLAGS);
con.executeStatement("attach database '" + downloadedDatabase.getAbsolutePath() + "' as '" + remoteDb + "'", DatabaseConnection.DEFAULT_RESULT_FLAGS);
After attaching the database, I create the following query to copy from the downloaded database (remoteDb) to the local database (localDb):
INSERT OR REPLACE INTO localDb.table_items (createdAt_device, updatedAt_device, _id, column_1, column_2, column_3, column_4, column_5, column_6) SELECT createdAt_device, updatedAt_device, _id, column_1, column_2, column_3, column_4, column_5, column_6 FROM remoteDb.table_items
Afterwards, I execute the following function from ORMLite:
con.executeStatement(query, flags);
The function works fine on Android version 4.1 (with SQLite 3.7.11) and higher. But I get the following Error on Android version 4.0 and 4.0.3 (with SQLite 3.7.4):
09-13 15:51:19.852: E/com.example.controller(1028): java.sql.SQLException: Problems executing INSERT OR REPLACE INTO localDb.table_items (createdAt_device, updatedAt_device, _id, column_1, column_2, column_3, column_4, column_5, column_6) SELECT createdAt_device, updatedAt_device, _id, column_1, column_2, column_3, column_4, column_5, column_6 FROM remoteDb.table_items Android statement: INSERT OR REPLACE INTO localDb.table_items (createdAt_device, updatedAt_device, _id, column_1, column_2, column_3, column_4, column_5, column_6) SELECT createdAt_device, updatedAt_device, _id, column_1, column_2, column_3, column_4, column_5, column_6 FROM remoteDb.table_items
09-13 15:51:19.852: E/com.example.controller(1028): at com.j256.ormlite.misc.SqlExceptionUtil.create(SqlExceptionUtil.java:22)
09-13 15:51:19.852: E/com.example.controller(1028): at com.j256.ormlite.android.AndroidCompiledStatement.execSql(AndroidCompiledStatement.java:185)
09-13 15:51:19.852: E/com.example.controller(1028): at com.j256.ormlite.android.AndroidDatabaseConnection.executeStatement(AndroidDatabaseConnection.java:134)
09-13 15:51:19.852: E/com.example.controller(1028): at com.example.controller$DatabaseTransferHandler.executeDatabaseTransfers(contoller.java:763)
09-13 15:51:19.852: E/com.example.controller(1028): at com.example.controller$DatabaseTransferHandler.access$0(contoller.java:740)
09-13 15:51:19.852: E/com.example.controller(1028): at com.example.controller.transferTables(contoller.java:494)
09-13 15:51:19.852: E/com.example.controller(1028): at com.example.controller.addElement(contoller.java:132)
09-13 15:51:19.852: E/com.example.controller(1028): at com.example.controller.addOrRemoveElements(contoller.java:109)
09-13 15:51:19.852: E/com.example.controller(1028): at com.example.controller.addElements(contoller.java:147)
09-13 15:51:19.852: E/com.example.controller(1028): at com.example.controller.download(contoller.java:254)
09-13 15:51:19.852: E/com.example.controller(1028): at com.example.controller.access$3(controller.java:204)
09-13 15:51:19.852: E/com.example.controller(1028): at com.example.controller$2.doInBackground(contoller.java:468)
09-13 15:51:19.852: E/com.example.controller(1028): at com.example.controller$2.doInBackground(contoller.java:1)
09-13 15:51:19.852: E/com.example.controller(1028): at android.os.AsyncTask$2.call(AsyncTask.java:264)
09-13 15:51:19.852: E/com.example.controller(1028): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
09-13 15:51:19.852: E/com.example.controller(1028): at java.util.concurrent.FutureTask.run(FutureTask.java:137)
09-13 15:51:19.852: E/com.example.controller(1028): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
09-13 15:51:19.852: E/com.example.controller(1028): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
09-13 15:51:19.852: E/com.example.controller(1028): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
09-13 15:51:19.852: E/com.example.controller(1028): at java.lang.Thread.run(Thread.java:856)
09-13 15:51:19.852: E/com.example.controller(1028): Caused by: android.database.sqlite.SQLiteDatabaseLockedException: database is locked
09-13 15:51:19.852: E/com.example.controller(1028): at android.database.sqlite.SQLiteStatement.native_executeSql(Native Method)
09-13 15:51:19.852: E/com.example.controller(1028): at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:90)
09-13 15:51:19.852: E/com.example.controller(1028): at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1899)
09-13 15:51:19.852: E/com.example.controller(1028): at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1839)
09-13 15:51:19.852: E/com.example.controller(1028): at android.database.sqlite.SQLiteDatabase.beginTransaction(SQLiteDatabase.java:661)
09-13 15:51:19.852: E/com.example.controller(1028): at android.database.sqlite.SQLiteDatabase.beginTransactionNonExclusive(SQLiteDatabase.java:576)
09-13 15:51:19.852: E/com.example.controller(1028): at android.database.sqlite.SQLiteStatement.acquireAndLock(SQLiteStatement.java:247)
09-13 15:51:19.852: E/com.example.controller(1028): at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:84)
09-13 15:51:19.852: E/com.example.controller(1028): at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1899)
09-13 15:51:19.852: E/com.example.controller(1028): at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1889)
09-13 15:51:19.852: E/com.example.controller(1028): at com.j256.ormlite.android.AndroidCompiledStatement.execSql(AndroidCompiledStatement.java:183)
09-13 15:51:19.852: E/com.example.controller(1028): ... 18 more
How can I solve this problem? Is there perhaps a better way to download large amounts of information to a device?
回答1:
I'm a coworker of the author of this question, and I managed to find a way to avoid this problem. I figured I'd post it here in case anyone else is stumbling across the same issue.
Android devices with that very specific OS version seemed to have a problem with this sequence of Ormlite commands:
DatabaseConnection con = null;
con = conSrc.getReadWriteConnection();
con.executeStatement("attach database '" + localDatabase.getAbsolutePath() + "' as '" + localDb + "'", DatabaseConnection.DEFAULT_RESULT_FLAGS);
con.executeStatement("attach database '" + downloadedDatabase.getAbsolutePath() + "' as '" + remoteDb + "'", DatabaseConnection.DEFAULT_RESULT_FLAGS);
I don't know if this is caused by the version of SQLite3 that comes preinstalled on these devices, or by something else.
Now we could avoid this because we could (luckily) avoid using Ormlite in this situation altogether. The SQLite statement "ATTACH DATABASE" does not need to be executed on a DatabaseConnection instance - it can be executed on the local database file. So instead of the former block, only this statement is necessary:
db.execSQL("ATTACH DATABASE '" + tempDb.getAbsolutePath() + "' AS '" + remoteDb + "'");
where db
is the SQLiteDatabase
instance of the local database.
The SQLite documentation states that:
"The ATTACH DATABASE statement adds another database file to the current database connection."
which is why no DatabaseConnection
instance is needed.
来源:https://stackoverflow.com/questions/18790978/ormlite-issue-with-inserting-tables-from-one-database-to-another-database-on-and