Android Sqlite 數(shù)據(jù)庫多線程操作

最近開發(fā)中,需要再多線程中操作數(shù)據(jù)庫,但是Android的sqlite數(shù)據(jù)庫是不能多線程寫讀寫的。
先看一下報的錯誤:

 android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5): , while compiling: PRAGMA journal_mode
   at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)

看一下代碼

public class DBTestActivity extends BaseActivity {


    private Button mAddStudent_bt;


    @Override
    protected void initView() {
        setContentView(R.layout.ac_dbtest);
        mAddStudent_bt=(Button)findViewById(R.id.ac_add_student_bt);
        mAddStudent_bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                addStudent();
            }
        });

    }

    private void addStudent() {
        //模擬1000個線程 加入數(shù)據(jù)庫
        for(int i=0;i<1000;i++){
            new Thread(){
                @Override
                public void run() {
                    super.run();
                    try {
                        //隨機休眠3秒以內(nèi)的時間
                        Thread.sleep((long) (Math.random( )*1000*3));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } 
                    Student s=new Student();
                    s.setStudentAge("1");
                    s.setStudentName("name:"+ new Date().getTime());
                    StudentDao.getInstance().addStudent(s);
                } 
            }.start();

        }

    }
}


public class StudentDao { 
    private static  volatile  StudentDao dao;   
    public static final String TAG="StudentDao"; 
    private StudentDao(){ 
    }

    public static  StudentDao getInstance(){
        if(dao==null){
            synchronized (StudentDao.class){
                if(dao==null){
                    dao=new StudentDao(); 
                }
            }
        }
        return dao;
    }

  //添加學(xué)生的方法,會在多個線程中調(diào)用
    public void addStudent(Student student){ 
        ContentValues contentValues=new ContentValues();
        contentValues.put("s_id", UUID.randomUUID().toString());
        contentValues.put("s_name", student.getStudentName());
        contentValues.put("s_age",student.getStudentAge()); 
        DbManager dBManager=new DbManager(BaseApp.getBaseApplicationContext());
        SQLiteDatabase writableDatabase  = dBManager.getWritableDatabase();
        long result=  writableDatabase.insertOrThrow("student",null,contentValues);//這里返回行號
        Log.e(TAG, "執(zhí)行的結(jié)果" +result+" "+Thread.currentThread().getName());
        writableDatabase.close();

    }
}

為了解決這個問題,我把所有的寫操作放在一個線程里,保證每次調(diào)用寫操作都只有一個線程,那么所有的 寫方法都必須枷鎖。
另外翻了一下資料,發(fā)現(xiàn)這個sqlite 的鎖是庫級別的,所以當(dāng)有多個線程的時候就會涉及到同步問題。
我在dao層寫了一個單線程的線程池,所有的寫的操作的方法在這個線程池里調(diào)用,就ok了。
代碼如下

public class StudentDao {

    private static volatile StudentDao dao;


    private static ExecutorService singThread
    public static final String TAG = "StudentDao";


    private StudentDao() {


    }

    public static StudentDao getInstance() {
        if (dao == null) {
            synchronized (StudentDao.class) {
                if (dao == null) {
                    dao = new StudentDao();
                    singThread= Executors.newSingleThreadExecutor();
                }
            }
        }
        return dao;
    }


    public void addStudent(final  Student student) {
        Runnable runnable=new Runnable() {
                @Override
                public void run() {
                    ContentValues contentValues = new ContentValues();
                    contentValues.put("s_id", UUID.randomUUID().toString());
                    contentValues.put("s_name", student.getStudentName());
                    contentValues.put("s_age", student.getStudentAge());
                    DbManager dBManager = new DbManager(BaseApp.getBaseApplicationContext());
                    SQLiteDatabase writableDatabase = dBManager.getWritableDatabase();
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    long result = writableDatabase.insertOrThrow("student", null, contentValues);//這里返回行號
                    Log.e(TAG, "執(zhí)行的結(jié)果1  " + result + " " + Thread.currentThread().getName());
                    writableDatabase.close();
                }
            };

        singThread.execute(runnable);

    }


    
}

簡單測試了一下,還沒有出現(xiàn)了報錯的問題,可能是我的數(shù)據(jù)比較小吧,找個機會多用點數(shù)據(jù)再測試一下。這種做法只是想的到一個臨時解決辦法,并不能夠做為方法放在項目里,如果有好的方案,可以留言告訴我一下,謝謝。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,979評論 25 709
  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,607評論 30 472
  • 青年手里拿著一支香煙 名為“藍色的愛” 尼古丁的氣息不重 卻多了幾分憂郁 地上的煙頭已有好幾 是因外頭的雨下了太久...
    清水Lee閱讀 221評論 0 0
  • 斷舍離的理念 斷=阻斷(不買當(dāng)前不需要的東西) 舍=舍棄(扔掉當(dāng)前不需要的東西) 離=脫離(脫離對東西的雜念,只挑...
    ba帝兒閱讀 227評論 0 0
  • 2017年5月26日 陰 無意間和小伙伴閑聊,勾起了曾經(jīng)的一段往事,若不是毫無防備它就跳了出來,我差點就徹底忘記...
    東尼日記閱讀 329評論 0 0

友情鏈接更多精彩內(nèi)容