2015-10-05 3 views
0

Я делаю некоторые тесты с моей фабрикой подключения к базе данных на Android.Проблемы с одновременным доступом к sqlitedatabase на 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(); 
     } 
    } 

excetion:

Е/АКР (9850): java.lang.IllegalStateException: попытка повторно открыть без того замкнутого объекта: SQLiteDatabase: /data/data/seduc.ma.com.br .siaepmovel/баз данных/database.sqlite Е/АКРА (9850): в android.database.sqlite.SQLiteClosable.acquireReference (SQLiteClosable.java:55) E/АКРА (9850): в android.database.sqlite. SQLiteDatabase.beginTransaction (SQLiteDatabase.java:503) E/ACRA (9850): at android.database.sqlite.SQLiteDatabase.beginTransaction (SQLiteDatabase.java:416) E/ACRA (9 850): в seduc.ma.com.br.siaepmovel.test.TesteActivity $ Worker.run (TesteActivity.java:45)

любая идея, почему?

====

мои вопросы отличается тем, что проблема возникает только с транзакциями.

+0

Простите меня, но вы, кажется, происходит из вашего пути, чтобы убедиться, что существует конфликт. – e4c5

+0

Возможный дубликат [Параллельный доступ к базе данных SQLite в Android-db уже закрыт] (http://stackoverflow.com/questions/10801119/concurrent-access-to-a-sqlite-database-in-android-db- уже -closed) – e4c5

+0

Почему вы не используете предоставленный SQLiteOpenHelper? http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html – Philio

ответ

0

В вашем коде у вас есть только одна ссылка на объект базы данных. Если один из рабочих вызывает метод close, другие работники не могут использовать закрытое соединение. Вы должны называть работников один за другим. Вы должны очистить контекстную ссылку в классе ConnectionFactory

Посмотрите на enter link description here

+0

, но мой близкий метод 'ConnectionFactory' только закрыл SqliteDatabase, если COUNTER был 0. Проблема в том, что мой' COUNTER' не работает, но почему? – user155542

+0

Когда три потока начинают соединение с db, вы создаете только одну ссылку. Поищите потоки один за другим. –

+0

Да, но мне нужно смоделировать реальный сценарий, когда потоки запускаются одновременно. Сценарий - это действия/несколько служб. – user155542

Смежные вопросы