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 Sqlite 数据库多线程操作)