Данные Изоляция с сервисами и 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 - это если вы находитесь в одном потоке и до завершения транзакции.