Android Sqlite 数据库多线程操作

最近开发中,需要再多线程中操作数据库,但是Android的sqlite数据库是不能多线程写读写的。
先看一下报的错误:

 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个线程 加入数据库
        for(int i=0;i<1000;i++){
            new Thread(){
                @Override
                public void run() {
                    super.run();
                    try {
                        //随机休眠3秒以内的时间
                        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;
    }

  //添加学生的方法,会在多个线程中调用
    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, "执行的结果" +result+" "+Thread.currentThread().getName());
        writableDatabase.close();

    }
}

为了解决这个问题,我把所有的写操作放在一个线程里,保证每次调用写操作都只有一个线程,那么所有的 写方法都必须枷锁。
另外翻了一下资料,发现这个sqlite 的锁是库级别的,所以当有多个线程的时候就会涉及到同步问题。
我在dao层写了一个单线程的线程池,所有的写的操作的方法在这个线程池里调用,就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, "执行的结果1  " + result + " " + Thread.currentThread().getName());
                    writableDatabase.close();
                }
            };

        singThread.execute(runnable);

    }


    
}

简单测试了一下,还没有出现了报错的问题,可能是我的数据比较小吧,找个机会多用点数据再测试一下。这种做法只是想的到一个临时解决办法,并不能够做为方法放在项目里,如果有好的方案,可以留言告诉我一下,谢谢。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 173,364评论 25 708
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,211评论 30 472
  • 青年手里拿着一支香烟 名为“蓝色的爱” 尼古丁的气息不重 却多了几分忧郁 地上的烟头已有好几 是因外头的雨下了太久...
    清水Lee阅读 207评论 0 0
  • 断舍离的理念 断=阻断(不买当前不需要的东西) 舍=舍弃(扔掉当前不需要的东西) 离=脱离(脱离对东西的杂念,只挑...
    ba帝儿阅读 198评论 0 0
  • 2017年5月26日 阴 无意间和小伙伴闲聊,勾起了曾经的一段往事,若不是毫无防备它就跳了出来,我差点就彻底忘记...
    东尼日记阅读 280评论 0 0