并发写入到Android数据库(从多服务)?数据库、Android

2023-09-12 07:58:55 作者:習慣成型

我已经与Android的SQLite数据库和并发写一个严重的问题。为了更好的解释,我会给你一个真实生活中的例子:

我有一个桌面widget,在这里我展示从我的数据库项目的列表(和背景我的DataService,这在定期从我的远程服务器收集新数据,并与他们更新我的数据库)。所以 - 当我在列表中点击一些项目,我需要在数据库中更新单击项目(=做写操作)。但是,当我完全在瞬间点击项目,当DataService是否已更新最新的数据在我的数据库,这当然是记录一个错误是这样的:

  android.database.sqlite.SQLiteException:错误code 5:数据库已锁定
 

通常情况下它很难模仿,但如果u DataService的调度运行,例如每10秒(只是为了演示),美国可以很容易模拟这个错误。

和我的问题是,如何处理呢?我读的文档,如果有在同一时间两个写事件,只有第一个会被执行,第二个将被记录为错误。它听起来很奇怪,必须有另外的选择,例如第二个写会等到第一次写入完成。或者,也许其他的解决办法?试图读取文档,但现在看来,这个项目是不是在谷歌文档很好的遮盖......几乎每一个信息,我有,我发现了比官方网页等。

PS:这是我的DBHelper类的我的缩短版:

 公共类DBHelper扩展SQLiteOpenHelper {

    私有静态最后弦乐TABLE_NEWS =新闻;
    私有静态最后弦乐COL_ID =ID;
    私有静态最后弦乐COL_TITLE =称号;
    私有静态最后弦乐COL_ALERT =警报;

    公共DBHelper(上下文的背景下){
        超级(上下文中,MY_DB_N​​AME,空,1);
    }

    @覆盖
    公共无效的onCreate(SQLiteDatabase DB){
        db.execSQL(CREATE TABLE+ TABLE_NEWS +(+ COL_ID +TEXT PRIMARY KEY,+ COL_TITLE +TEXT+ COL_ALERT +整数+));
    }

    @覆盖
    公共无效onUpgrade(SQLiteDatabase分贝,INT oldVersion,诠释静态网页){
        db.execSQL(DROP TABLE IF EXISTS+ TABLE_NEWS);
        的onCreate(DB);
    }

    公共无效addRecords(ArrayList中< NewsItem>项目){
        SQLiteDatabase DB = this.getWritableDatabase();
        的for(int i = 0; I< items.size();我++){
            NewsItem项= items.get(ⅰ);
            ContentValues​​值=新ContentValues​​();
            values​​.put(COL_ID,item.getId());
            values​​.put(COL_TITLE,item.getTitle());
            values​​.put(COL_ALERT,item.getAlertMe());
            db.insert(TABLE_NEWS,空,价值观);
        }
        db.close();
    }

    公众诠释updateRecord(NewsItem项目){
        SQLiteDatabase DB = this.getWritableDatabase();
        ContentValues​​值=新ContentValues​​();
        values​​.put(COL_ALERT_ME,item.getAlertMe());
        诠释更新= db.update(TABLE_NEWS,价值观,COL_ID +=?,新的String [] {item.getId()});
        db.close();
        返回更新;
    }
}
 
android 怎么把数据库里的数据写入到短信的联系人里

解决方案

您需要使用一个单独的 SQLiteDatabase 对象,所有线程(及其托管的组件),以得到线程安全。让你的 DBHelper 是个单,或使用的ContentProvider ,以达到这种效果。

I've a serious problem with android sqlite database and concurrent writing. For better explanations, I will give you a real life example:

I've an desktop widget, where I'm showing a list of items from my database (and on background I have DataService, which in regular intervals collects fresh data from my remote server, and update my database with them). So - when i click on some item in list, i need to update clicked item (=do write operation) in database. BUT when i click on item exactly in moment, when DataService is updating fresh data in my database, it of course logs an error like this:

android.database.sqlite.SQLiteException: error code 5: database is locked

Normally its hard to simulate, but if u schedule DataService to run for example every 10 seconds (just for demonstration), u can simulate this error very easily.

And my question is, how to handle this? I read in docs, that if there are two write events in same time, only first will be executed, second will be logged as an error. Its sounds strange, there must be another options, for example the second write would wait until first write finish. Or maybe other solution? Trying to read docs, but it seems, that this item is not very good covered in google docs...Almost every info I have, I found on other than official pages.

PS: This is my shortened version of my DBHelper class:

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

解决方案

You need to use a single SQLiteDatabase object, across all threads (and their hosting components), to get thread safety. Make your DBHelper be a singleton, or use a ContentProvider, to achieve this effect.

 
精彩推荐