2014-11-04 48 views
1

我已经实施了SQliteOpenHelper与单例模式,并且它工作良好,直到现在。但考虑到以下顺序:数据隔离与服务和Singleton 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(); 
} 
+0

你应该检查了这一点:http://blog.lemberg.co.uk/concurrent-database-access – 2014-11-04 09:28:59

+0

@ user2247689谢谢我已阅读同一文章在3个不同的网站:)但它不处理交易或隔离,所以与问题无关。 – faizal 2014-11-04 09:31:28

+0

对不起,我没有正确地阅读这个问题。处理服务有点棘手,特别是当它们必须并发时。基本上我猜你会不得不使用'消息'?请参阅http://developer.android.com/guide/components/bound-services.html#Messenger – 2014-11-04 09:39:51

回答

2
  1. 服务的主线程上运行。它没有它自己的线程。它只有在主线程完成工作后才会执行。因此,在事务在活动/片段中运行时不会有服务启动的风险。

  2. 两个线程不能访问相同的SQliteDatabase连接。该系统旨在允许每个线程从池中访问唯一的连接。如果没有可用的连接,其他线程将等待一个。如果需要等待足够长的时间,您会看到类似于我在下面的手机中看到的logcat警告。所以单例模式补充了SQLite的线程安全性。

    W/SQLiteConnectionPool(12695): The connection pool for database 'xyz' has been unable to grant a connection to thread 6386 (AsyncTask #2) with flags 0x1 for 4.0 seconds. W/SQLiteConnectionPool(12695): Connections: 0 active, 1 idle, 0 available.

  3. 由于#2的结果,还有另一个线程,如果你使用一个单独读取未提交的数据没有可能的方式。即使你不使用单例,SQLite默认提供了连接之间的数据隔离。见https://www.sqlite.org/isolation.html

结论:与一个单身读取未提交的数据的唯一方法是,如果你是在同一个线程,并在交易结束之前。

+1

请注意,虽然如果未预先写入日志记录未启用,则连接池当前设置为最大值1,但实际上这不是必需的,将来可能会更改。但是,每个线程将使用不同的会话并从池中获取唯一的连接。 SQLite当然仍然会实现它自己的锁定和并发模型。 – corsair992 2014-11-04 14:41:57

+0

谢谢@ corsair992。我将SQLiteDatabase实例与连接实例混淆了。我编辑了#2以反映您的评论。 – faizal 2014-11-04 14:56:06