Android 使用服务和单例SQliteOpenHelper进行数据隔离

Android 使用服务和单例SQliteOpenHelper进行数据隔离,android,android-sqlite,Android,Android Sqlite,我已经用单例模式实现了SQliteOpenHelper,到目前为止它运行良好。但是考虑下面的顺序: 片段启动事务以更新记录 触发读取更新数据的服务 事务因某种原因失败并被回滚 服务将处理稍后回滚的未提交数据。因此,单例模式与服务的耦合似乎会导致数据隔离问题。然而,我读过很多推荐单身人士的帖子。使用单例时如何处理这种情况 public class MyApplication extends Application{ private static MyApplication instan

我已经用单例模式实现了SQliteOpenHelper,到目前为止它运行良好。但是考虑下面的顺序:

  • 片段启动事务以更新记录
  • 触发读取更新数据的服务
  • 事务因某种原因失败并被回滚
服务将处理稍后回滚的未提交数据。因此,单例模式与服务的耦合似乎会导致数据隔离问题。然而,我读过很多推荐单身人士的帖子。使用单例时如何处理这种情况

public class MyApplication extends Application{
    private static MyApplication instance;
    public MyApplication(){
        instance = this;
    }
    public static Context getContext(){
        return instance;
    }
}

public class LocalDBHelper extends SQLiteOpenHelper{
    private static final int DATABASE_VERSION = 1;
    private static final String DATABASE_NAME = "MyDB";
    private static final String LOG_TAG = "LocalDBHelper";

    private static LocalDBHelper instance = null;
    /*private constructor to avoid direct instantiation by other classes*/
    private LocalDBHelper(){
        super(MyApplication.getContext(), DATABASE_NAME, null, DATABASE_VERSION);
    }
    /*synchronized method to ensure only 1 instance of LocalDBHelper exists*/
    public static synchronized LocalDBHelper getInstance(){
        if(instance == null){
            instance = new LocalDBHelper();
        }
        return instance;
    }
    ...
    ...
}
与事务一起使用:

SQLiteDatabase db = LocalDBHelper.getInstance().getWritableDatabase();
db.beginTransaction();
try{
....
...
db.setTransactionSuccessful();
}catch(Exception e){
    e.printStackTrace();
}
finally{
    db.endTransaction();
}
  • 服务在主线程上运行。它没有自己的线程。它将仅在主线程完成其工作后执行。因此,当事务在活动/片段中运行时,不存在启动服务的风险

  • 两个线程无法访问相同的
    SQliteDatabase
    连接。系统设计为允许每个线程访问池中的唯一连接。如果没有可用的连接,其他线程将等待一个。如果它必须等待足够长的时间,你会看到一个类似于我在手机下面看到的logcat警告。因此,单例模式补充了SQLite的线程安全性

    W/SQLiteConnectionPool(12695):数据库“xyz”的连接池在4.0秒内无法授予与带有标志0x1的线程6386(AsyncTask#2)的连接。
    W/SQLiteConnectionPool(12695):连接:0个活动,1个空闲,0个可用。

  • 作为#2的结果,如果使用单线程,则不可能通过其他线程读取未提交的数据。即使不使用单例,SQLite在默认情况下也会在连接之间提供数据隔离。看


  • 结论:使用单例读取未提交数据的唯一方法是,如果您在同一线程上,并且在事务结束之前。

    您应该检查以下内容:@user2247689谢谢我在3个不同的站点上读过同一篇文章:),但它不处理事务或隔离,这与问题无关。对不起,我没有正确阅读问题。处理服务有点棘手,尤其是当它们必须并发时。基本上我猜你必须使用“消息”吗?请参见此
    SQLiteDatabase
    维护由线程本地数据库会话获取的活动连接池`-多个线程永远无法获取相同的连接。@corsair992!您完全正确请注意,如果未启用预写日志记录,则连接池当前设置为最大值1,但这实际上不是必需的,将来可能会更改。但是,每个线程将使用不同的会话,并从池中获取唯一的连接。SQLite当然仍然会实现自己的锁定和并发模型。谢谢@corsair992。我混淆了SQLiteDatabase实例和连接实例。我编辑了#2以反映您的评论。