提供服务和辛格尔顿SQliteOpenHelper数据隔离 [英] data Isolation with services and Singleton SQliteOpenHelper

查看:99
本文介绍了提供服务和辛格尔顿SQliteOpenHelper数据隔离的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经实现了Singleton模式的SQliteOpenHelper,它工作正常至今。但考虑到以下顺序:


  • 片段开始一个事务更新记录

  • 系统服务被触发读取更新后的数据

  • 交易由于某种原因失败和被回滚

该服务将已处理了以后得到了回滚未提交的数据。如此看来,再加上服务Singleton模式会导致数据隔离的问题。然而,我看过无数的帖子,建议单身。如何使用单当一个处理这种情况?

 公共类MyApplication的扩展应用{
    私有静态MyApplication的实例;
    公共所有MyApplication(){
        例如=这一点;
    }
    公共静态上下文的getContext(){
        返回实例;
    }
}公共类LocalDBHelper扩展SQLiteOpenHelper {
    私有静态最终诠释DATABASE_VERSION = 1;
    私有静态最后弦乐DATABASE_NAME =MYDB;
    私有静态最后弦乐LOG_TAG =LocalDBHelper;    私有静态LocalDBHelper例如= NULL;
    / *私有构造函数来避免直接实例化其它类* /
    私人LocalDBHelper(){
        超(MyApplication.getContext(),DATABASE_NAME,空,DATABASE_VERSION);
    }
    / *同步的方法,以确保只有1实例LocalDBHelper存在* /
    公共静态同步LocalDBHelper的getInstance(){
        如果(例如== NULL){
            例如=新LocalDBHelper();
        }
        返回实例;
    }
    ...
    ...
}

与交易用法:

  SQLiteDatabase DB = LocalDBHelper.getInstance()getWritableDatabase()。
db.beginTransaction();
尝试{
....
...
db.setTransactionSuccessful();
}赶上(例外五){
    e.printStackTrace();
}
最后{
    db.endTransaction();
}


解决方案

  1. 一个服务的主线程上运行。它不具有它自己的线程。它将执行只有在主线程已经完成了它的工作。所以当交易是在活动/片段开始运行没有一个服务的风险。


  2. 两个线程不能访问相同的 SQliteDatabase 连接。该系统被设计为允许从池中的唯一连接每一个线程访问。如果没有连接可用,其他线程(S)将等待之一。如果它必须等待足够长,你会看到一个警告logcat中类似于我下面我的手机上看到的。因此,一个单例模式补充的SQLite的线程安全。

    W / SQLiteConnectionPool(12695):对数据库'某某'的连接池已经无法给予的连接线程与标志为0x1 6386(AsyncTask的#2)4.0秒。
    W / SQLiteConnectionPool(12695):连接:0活跃,1空闲,0可用


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


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

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.

  2. Two threads cannot access the same SQliteDatabase connection. 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.

  3. 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.

这篇关于提供服务和辛格尔顿SQliteOpenHelper数据隔离的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆