美文网首页Android收藏
Android Sqlite 数据库多线程操作

Android Sqlite 数据库多线程操作

作者: 972ac0603088 | 来源:发表于2017-05-18 19:33 被阅读304次

    最近开发中,需要再多线程中操作数据库,但是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 Sqlite 数据库多线程操作

        本文链接:https://www.haomeiwen.com/subject/mhejxxtx.html