Данные Изоляция с сервисами и Singleton SQliteOpenHelper
Я реализовал SQliteOpenHelper с шаблоном Singleton и работает до сих пор. Но рассмотрим следующую последовательность:
- Фрагмент начинает транзакцию для обновления записей
- Служба запускается, считывая обновленные данные
- Сделка по какой-то причине не работает и возвращается.
Служба обработала бы незафиксированные данные, которые впоследствии были отброшены. Таким образом, кажется, что одноэлементный шаблон в сочетании с сервисом вызывает проблемы с изоляцией данных. Тем не менее, я прочитал множество сообщений, рекомендующих синглтон. Как обрабатывать этот сценарий при использовании 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;
}
...
...
}
Использование транзакций:
SQLiteDatabase db = LocalDBHelper.getInstance().getWritableDatabase();
db.beginTransaction();
try{
....
...
db.setTransactionSuccessful();
}catch(Exception e){
e.printStackTrace();
}
finally{
db.endTransaction();
}
Ответы
Ответ 1
-
Служба работает по основному потоку. У него нет собственной нити. Он будет выполняться только после того, как основной поток завершит работу. Таким образом, нет никакого риска для службы, начиная с транзакции в действии/фрагменте.
-
Два потока не могут получить доступ к одному и тому же соединению 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.
-
Как следствие №2, нет возможности читать незафиксированные данные другим потоком, если вы используете одноэлемент. Даже если вы не используете синглтон, SQLite по умолчанию обеспечивает изоляцию данных между соединениями. См. https://www.sqlite.org/isolation.html.
Вывод:. Единственный способ прочитать незафиксированные данные с помощью singleton - это если вы находитесь в одном потоке и до завершения транзакции.