简体   繁体   English

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

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

I am making some tests with my database connection factory 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();
        }
    }

}

my DatabaseManager (I made this class for scenarios of concurrent access to database) 我的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 +" ======================");
    }


}

my class of test: 我的测试类别:

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();
            }
        }
    }

}

this works perfectly, but when I use transactions, I receive some exceptions: 这很完美,但是当我使用事务时,我会收到一些例外:

    @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();
        }
    }

excetion: 兴奋:

E/ACRA ( 9850): java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/data/seduc.ma.com.br.siaepmovel/databases/database.sqlite E/ACRA ( 9850): at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:55) E/ACRA ( 9850): at android.database.sqlite.SQLiteDatabase.beginTransaction(SQLiteDatabase.java:503) E/ACRA ( 9850): at android.database.sqlite.SQLiteDatabase.beginTransaction(SQLiteDatabase.java:416) E/ACRA ( 9850): at seduc.ma.com.br.siaepmovel.test.TesteActivity$Worker.run(TesteActivity.java:45) 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)

any idea why? 知道为什么吗?

==== ====

my questions is different because the problem occurs only with transactions. 我的问题有所不同,因为问题仅发生在交易中。

In your code you have only one reference to database object. 在您的代码中,您只有一个对数据库对象的引用。 If one of workers call close method, other workers can not use closed connection. 如果其中一个工作人员调用了关闭方法,其他工作人员将无法使用关闭的连接。 You should call workers one after another. 您应该一个接一个地打电话给工人。 You should clear context reference in your class ConnectionFactory 您应该在类ConnectionFactory中清除上下文引用

Look at enter link description here 此处查看输入链接说明

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

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