问题
I have implemented the SQliteOpenHelper with a Singleton pattern and it works fine till now. But consider the below sequence :
- A fragment starts a transaction to updating records
- A service gets triggered that reads the updated data
- Transaction fails for some reason and gets rolled back
The service would have processed uncommitted data that got rolled back later. So it seems that a singleton pattern coupled with a service causes problems with data isolation. Yet i have read numerous posts recommending a singleton. How does one handle this scenario when using a singleton?
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;
}
...
...
}
Usage with transactions :
SQLiteDatabase db = LocalDBHelper.getInstance().getWritableDatabase();
db.beginTransaction();
try{
....
...
db.setTransactionSuccessful();
}catch(Exception e){
e.printStackTrace();
}
finally{
db.endTransaction();
}
回答1:
A service runs on the main thread. It does not have it's own thread. It will execute only after the main thread has finished it's work. So there is no risk of a service starting when a transaction is running in an activity/fragment.
Two threads cannot access the same
SQliteDatabaseconnection. The system is designed to allow every thread access to a unique connection from the pool. If there are no connections available, the other thread(s) will wait for one. If it has to wait long enough, you will see a logcat warning similar to what i see on my phone below. So a singleton pattern complements the SQLite's thread safety.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.As a consequence of #2, there is no possible way to read uncommitted data by another thread if you use a singleton. Even if you don't use a singleton, SQLite by default provides data isolation between connections. See https://www.sqlite.org/isolation.html.
Conclusion : The only way to read uncommitted data with a singleton is if you are on the same thread and before the transaction has ended.
来源:https://stackoverflow.com/questions/26731217/data-isolation-with-services-and-singleton-sqliteopenhelper