Równoczesne zapisywanie do bazy danych Android (z wielu usług)?
Mam poważny problem z bazą danych SQL sqlite i jednoczesnym pisaniem. Aby uzyskać lepsze wyjaśnienia, dam ci prawdziwy przykład:
Mam widżet na pulpicie, w którym pokazuję listę elementów z mojej bazy danych (w tle mam DataService, która w regularnych odstępach czasu zbiera nowe dane z mojego zdalnego serwera i aktualizuję ich bazę danych). Więc - kiedy klikam na jakiś element na liście, muszę zaktualizować kliknięty element (= wykonać operację zapisu) w bazie danych. ALE gdy klikam na element dokładnie w momencie, gdy DataService aktualizuje świeże dane w mojej bazie danych, to oczywiście rejestruje taki błąd:
android.database.sqlite.SQLiteException: error code 5: database is locked
Zwykle jest to trudne do symulacji, ale jeśli zaplanujesz usługę DataService na przykład co 10 sekund (tylko dla celów demonstracyjnych), możesz bardzo łatwo symulować ten błąd.
A moje pytanie brzmi, jak sobie z tym poradzić? Czytałem w docs, że jeśli są dwa zdarzenia zapisu w tym samym czasie, tylko pierwszy zostanie wykonany, drugi zostanie zarejestrowany jako błąd. Brzmi dziwnie, muszą istnieć inne opcje, na przykład drugi zapis będzie czekał do pierwszego zapisu zakończenia. A może inne rozwiązanie? Próbuję czytać dokumenty, ale wygląda na to, że ten artykuł nie jest zbyt dobrze opisany w dokumentach google ... Prawie każda informacja, jaką mam, znalazłem na innych niż oficjalnych stronach.
PS: To jest moja skrócona wersja mojej klasy DBHelper:
public class DBHelper extends SQLiteOpenHelper {
private static final String TABLE_NEWS = "News";
private static final String COL_ID = "id";
private static final String COL_TITLE = "title";
private static final String COL_ALERT = "alert";
public DBHelper(Context context) {
super(context, "MY_DB_NAME", null, 1);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE_NEWS + "(" + COL_ID + " TEXT PRIMARY KEY," + COL_TITLE + " TEXT," + COL_ALERT + " INTEGER" + ")");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NEWS);
onCreate(db);
}
public void addRecords(ArrayList<NewsItem> items) {
SQLiteDatabase db = this.getWritableDatabase();
for (int i = 0; i < items.size(); i++) {
NewsItem item = items.get(i);
ContentValues values = new ContentValues();
values.put(COL_ID, item.getId());
values.put(COL_TITLE, item.getTitle());
values.put(COL_ALERT, item.getAlertMe());
db.insert(TABLE_NEWS, null, values);
}
db.close();
}
public int updateRecord(NewsItem item) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(COL_ALERT_ME, item.getAlertMe());
int updated = db.update(TABLE_NEWS, values, COL_ID + " = ?", new String[] { item.getId() });
db.close();
return updated;
}
}