j256 / ormlite-android

ORMLite Android functionality used in conjunction with ormlite-core
http://ormlite.com/
ISC License
1.59k stars 367 forks source link

cannot rollback - no transaction is active (code 1) in RuntimeExceptionDao#callBatchTasks #34

Closed koral-- closed 9 years ago

koral-- commented 9 years ago

The following exception has been encountered:

android.database.sqlite.SQLiteException: cannot rollback - no transaction is active (code 1)
    at android.database.sqlite.SQLiteConnection.nativeExecute(Native Method)
    at android.database.sqlite.SQLiteConnection.execute(SQLiteConnection.java:679)
    at android.database.sqlite.SQLiteSession.endTransactionUnchecked(SQLiteSession.java:439)
    at android.database.sqlite.SQLiteSession.endTransaction(SQLiteSession.java:401)
    at android.database.sqlite.SQLiteDatabase.endTransaction(SQLiteDatabase.java:522)
    at com.j256.ormlite.android.AndroidDatabaseConnection.setAutoCommit(SourceFile:77)
    at com.j256.ormlite.misc.TransactionManager.callInTransaction(SourceFile:197)
    at com.j256.ormlite.stmt.StatementExecutor.callBatchTasks(SourceFile:553)
    at com.j256.ormlite.dao.BaseDaoImpl.callBatchTasks(SourceFile:633)
    at com.j256.ormlite.dao.RuntimeExceptionDao.callBatchTasks(SourceFile:534)

ormlite-android:4.48 ormlite-core:4.48 Android: 4.1.2 Only DB operations in Callable are createOrUpdate.

j256 commented 9 years ago

Sorry for the delay. Were you able to reproduce this? Can you write a junit that demonstrates the issue? We are getting ready to [finally] push 4.49 and I'd like to make sure this isn't an issue.

koral-- commented 9 years ago

I haven't tried to reproduce that. Error has been reported by ACRA from some user. Currently there is several such reports and additionally several almost the same, with message: disk I/O error (code 778) all of them comes from Samsung GT-I9100 with android 4.1.2 (not from one app installation). That may be a bug(s) in particular version of sqlite native library.

kpgalligan commented 9 years ago

If you're seeing this on a single device/version, that will be very difficult to reproduce. Any idea if this is from a single user? The sqlite error code specifically suggests a hardware issue. Not sure that is the issue, but if its possibly a single user, its fairly likely. https://www.sqlite.org/rescode.html#ioerr_write

koral-- commented 9 years ago

I've got 10 automatic reports (sent by ACRA) from 3 different installations. If we assume that users has not cleaned app data nor reinstall an app then then there are 3 users.

j256 commented 9 years ago

Hrm. Interesting. Is there any chance that multiple threads are using callBatchTasks(...) at the same time? Since there is one database connection, two threads might be clashing when they try to start and end transactions.

j256 commented 9 years ago

I've just added the following to the notes in Dao.callBatchTasks(...):

NOTE: Depending on your underlying database implementation and whether or not you are working with a single database connection, you may need to synchronize around calls to this method otherwise the database transactions that are used may clash when called simultaneously from multiple threads. You may also need to synchronize other calls to transactions and dao.setAutoCommit(...).

j256 commented 9 years ago

Related to https://github.com/j256/ormlite-android/issues/16

j256 commented 9 years ago

Reopen this issue if threading is not the problem. Thanks.

j256 commented 9 years ago

I guess one question would be should ORMLite be forcing the synchronization?

koral-- commented 9 years ago

It was possible that multiple threads used transactions at the same time. Isn't there any mechanism that prevents such clashes in Android SQLite related classes? I see eg. SQLiteSession#TRANSACTION_MODE_EXCLUSIVE.

kpgalligan commented 9 years ago

I wouldn't do any locking in ORMLite for the sake of Android. If you're using one SqliteOpenHelper globally in your app, multiple threads are OK. There's synchronization happening at the Java level. If you have multiple open helper instances, or multiple processes accessing the db, then you have issues.

If you're having multi-threading issues, we'd need to see more code and how you're accessing the db. This is very well word territory from an Android perspective, though. If there's a threading issue, its pretty much always that you have more than one connection open.

kpgalligan commented 9 years ago

For reference: http://stackoverflow.com/questions/2493331/what-are-the-best-practices-for-sqlite-on-android/3689883#3689883

koral-- commented 9 years ago

I am using one global helper instance, app has only one process and I am not touching the database without OrmLite. Instance of the helper is acquired like this: OpenHelperManager.getHelper(this, DatabaseHelper.class); in application's onCreate() only, DatabaseHelper extends OrmLiteSqliteOpenHelper. Any more info would be helpful?

kpgalligan commented 9 years ago

Can't really do anything without a way to reproduce the issue. at a minimum we'd need to see your code. We're just looking at a stack trace and a description of the issue.

koral-- commented 9 years ago

Here it is:

    final Calendar cal = getCalendarWithTimezone();
        final RuntimeExceptionDao<LocalUsage, Integer> localUsageDao = getLocalUsageDao();

        final long oldestTimestamp = getOldestTimestamp();
        final long baseUsage = getBaseUsage();
        final long bootTimestamp = getBootTimestamp();

        localUsageDao.callBatchTasks(new Callable<Void>()
        {
            @Override
            public Void call() throws Exception
            {
                while (cal.getTimeInMillis() > oldestTimestamp)
                {
                    long usage = cal.getTimeInMillis() > bootTimestamp ? baseUsage : -1L;
                    localUsageDao.createOrUpdate(new LocalUsage(cal.getTimeInMillis(), usage));
                    cal.add(Calendar.DAY_OF_MONTH, -1);
                }
                return null;
            }
        });

LocalUsage constructor does nothing except assigning field values.

I guess that database file could not be saved when commiting transaction due to some I/O failure (as described in your link). Some bug related to file I/O may exist in that particular ROM of SGS2. Maybe it will be possible to reproduce that with messing up with database file when transaction is in progress eg. corrupting it.