android上的Ormlite TransactionManager同步对我有用,但文档说不然

时间:2016-01-20 14:45:42

标签: android transactions ormlite race-condition

我希望在我的Ormlite模型上实现一个脏位。在与服务器同步过程中,我需要确保不覆盖用户编辑的行。为此,我需要一种方法来保证在同步线程读取脏位和更新值之间不允许用户编辑。

我正在使用单例DatabaseHelper类:

public class DatabaseHelper extends OrmLiteSqliteOpenHelper {

    private static DatabaseHelper databaseHelper = null;
    private Dao<FormField, String> formFieldDao = null;

    public static DatabaseHelper getHelper() {
        if (databaseHelper == null) {
            databaseHelper =
                    OpenHelperManager.getHelper(MyGoldCare.getAppContext(), DatabaseHelper.class);
        }
        return databaseHelper;
    }
  public Dao<FormField, String> getFormFieldDao() throws java.sql.SQLException {
    if (formFieldDao == null) {
        formFieldDao = getDao(FormField.class);
    }
    return formFieldDao;
}

我的第一个绝迹是读取脏位并更新事务中的值。我写了一个简单的测试,看看这是否适用于没有竞争条件的情况:

public class TestTransactionWriter implements Runnable {

    FormField formField;
    long sleepTime;

    public TestTransactionWriter(FormField formField, long sleepTime){
        this.formField = formField;
        this.sleepTime = sleepTime;
    }
    @Override
    public void run() {
        android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
        try {
            TransactionManager.callInTransaction(DatabaseHelper.getHelper().getConnectionSource(), new Callable<Void>(){
             public Void call() throws SQLException,InterruptedException{
            for (int i = 0; i < 10; i++) {
                DatabaseHelper.getHelper().getFormFieldDao().refresh(formField);
                Thread.sleep(sleepTime);
                Integer v = Integer.parseInt(formField.getValue());
                v++;
                formField.setValue(v.toString());
                DatabaseHelper.getHelper().getFormFieldDao().update(formField);
            }
            return null;
            }
             });
            }catch (SQLException se){
               Log.e("TEST",se.toString());
            }
    }
}

然后我用上面的runnable启动了2个线程:

            formField.setValue("0");
            DatabaseHelper.getHelper().getFormFieldDao().update(formField);
            TestTransactionWriter testTransactionWriter = new TestTransactionWriter(formField,1500);
            Thread thread = new Thread(testTransactionWriter) ;
            thread.start();

            TestTransactionWriter testTransactionWriter1 = new TestTransactionWriter(formField,2000);
            Thread thread1 = new Thread(testTransactionWriter) ;
            thread1.start();

        }catch (SQLException se){
            Log.e(LOG_TAG,se.toString());
        }
    }

我得到了我期待的结果。每次测试时,最终值为20。当我在交易中删除呼叫时,我得到竞争条件。我注意到的另一件事是,当这些线程正在运行时,我无法从数据库中读取任何值(其他表),并且UI暂时冻结。

为了确认我的测试我决定阅读Ormlite的来源,我发现了以下警告:

 * WARNING: it is up to you to properly synchronize around this method if multiple threads are using a
 * connection-source which works gives out a single-connection. The reason why this is necessary is that multiple
 * operations are performed on the connection and race-conditions will exist with multiple threads working on the
 * same connection.
 * </p>
 * 
 * @param callable
 *            Callable to execute inside of the transaction.
 * @return The object returned by the callable.
 * @throws SQLException
 *             If the callable threw an exception then the transaction is rolled back and a SQLException wraps the
 *             callable exception and is thrown by this method.
 */
public <T> T callInTransaction(final Callable<T> callable) throws SQLException {
    return callInTransaction(connectionSource, callable);

在我的情况下,即使我没有自己同步,测试也没有产生竞争条件?是不是有一些SQLlite数据库锁被踢了?考虑到我使用单例数据库助手的面孔,是否存在其他级别的同步?

1 个答案:

答案 0 :(得分:1)

  

在我的情况下,即使我没有自己同步,测试也没有产生竞争条件?是不是有一些SQLlite数据库锁被踢了?

不,但我怀疑某些Sqlite锁定已经启动。该WARNING适用于所有ORMLite后端,包括允许多个线程连接到同一数据库的JDBC。

  

为此,我需要一种方法来保证在同步线程读取脏位和更新值之间不允许用户编辑。

我要看看ORMLite中的version = true支持,它在数据级别对此进行验证。它适用于从多个客户端对数据库进行多个连接的分布式系统,但它也可能对您有所帮助。请参阅version field documentation