繁体   English   中英

在Android上并发访问sqlitedatabase时遇到问题?

[英]Problems with concurrent access to sqlitedatabase on Android?

我正在使用Android上的数据库连接工厂进行一些测试。

public class ConnectionFactory {

    private Context context;
    private SQLiteDatabase w;

    private static DatabaseManager manager;

    public ConnectionFactory(Context context) {
        this.context = context;
    }

    public synchronized SQLiteDatabase getDatabase(){
        if(manager == null){
            DatabaseManager.init(new DatabaseHelper(context));
            manager = DatabaseManager.getInstance();
        }

        return w == null || !w.isOpen() ? w = manager.getDatabase() : w;
    }

    public synchronized void close() {
        if(w != null && w.isOpen()){
            manager.close();
        }
    }

}

我的DatabaseManager(我为同时访问数据库的场景制作了此类)

public class DatabaseManager {

    private static SQLiteOpenHelper helper;
    private static DatabaseManager instance;
    private static int COUNTER = 0;

    private SQLiteDatabase database;

    private DatabaseManager(){}

    public static synchronized void init(SQLiteOpenHelper first) {
        if (instance == null) {
            helper = first;

            instance = new DatabaseManager(){

                @Override
                protected void finalize() throws Throwable {
                    helper.close();
                    COUNTER = 0;

                    helper = null;
                }

            };

        }
    }

    public static synchronized DatabaseManager getInstance() {
        if (instance == null) {
            throw new IllegalStateException("O método init deve ser chamado antes deste método.");
        }

        return instance;
    }

    public synchronized SQLiteDatabase getDatabase() {
        COUNTER++;

        if(COUNTER == 1) {
            Log.i("SIAEP", "====================== ABRINDO UMA NOVA REFERENCIA DE SQLITEDATABASE ======================");
            database = helper.getWritableDatabase();
        }

        Log.i("SIAEP", "====================== DATABASE MANAGER COUNTER 'getDatabase': "+ COUNTER +" ======================");

        return database;
    }

    public synchronized void close() {
        if(COUNTER != 0)
            COUNTER--;

        if(COUNTER == 0) {

            if(database.inTransaction()){
                database.endTransaction();
            }

            Log.i("SIAEP", "====================== FECHANDO A REFERENCIA DE SQLITEDATABASE ======================");

            database.close();
        }

        Log.i("SIAEP", "====================== DATABASE MANAGER COUNTER 'close': "+ COUNTER +" ======================");
    }


}

我的测试类别:

public class TesteActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Worker t1 = new Worker(this);
        Worker t2 = new Worker(this);

        t1.start();
        t2.start();
    }

    public static class Worker extends Thread {

        private Activity instance;

        public Worker(Activity instance) {
            this.instance = instance;
        }

        @Override
        public void run() {

            ConnectionFactory factory = new ConnectionFactory(instance);

            for (int i = 0; i < 100; i++) {
                SQLiteDatabase database = factory.getDatabase();
                factory.close();
            }
        }
    }

}

这很完美,但是当我使用事务时,我会收到一些例外:

    @Override
    public void run() {

        ConnectionFactory factory = new ConnectionFactory(instance);

        for (int i = 0; i < 100; i++) {
            SQLiteDatabase database = factory.getDatabase();

            database.beginTransaction();
            database.setTransactionSuccessful();
            database.endTransaction();

            factory.close();
        }
    }

兴奋:

E / ACRA(9850):java.lang.IllegalStateException:尝试重新打开一个已经关闭的对象:SQLiteDatabase:/data/data/seduc.ma.com.br.siaepmovel/databases/database.sqlite E / ACRA( 9850):位于android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:55)E / ACRA(9850):位于android.database.sqlite.SQLiteDatabase.beginTransaction(SQLiteDatabase.java:503)E / ACRA(9850) :位于android.database.sqlite.SQLiteDatabase.beginTransaction(SQLiteDatabase.java:416)E / ACRA(9850):位于seduc.ma.com.br.siaepmovel.test.TesteActivity $ Worker.run(TesteActivity.java:45)

知道为什么吗?

====

我的问题有所不同,因为问题仅发生在交易中。

在您的代码中,您只有一个对数据库对象的引用。 如果其中一个工作人员调用了关闭方法,其他工作人员将无法使用关闭的连接。 您应该一个接一个地打电话给工人。 您应该在类ConnectionFactory中清除上下文引用

此处查看输入链接说明

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM