Android数据库并发操作解决思路

来源: lizhengwei1989 发布时间:2018-11-30 17:48:25 阅读量:984

数据库作为Android数据存储重要的一部分,相信很多应用中都会用到,面试也会遇到很多关于数据库的问题。实际开发中我没遇到过特别复杂的数据库使用,所以对这一块的优化没怎么研究过。 

以前面试的时候被问到过这么一个问题: 

面试官:数据库并发访问怎么处理? 

我:给增删改查方法加锁。 

面试官:那样会有什么问题? 

我:效率低。 

面试官:怎么解决? 

我:不太清楚啊。。。


我一直认为Android开发不会涉及到数据库大量线程访问数据库的问题,所以方法加锁的效率问题是可以容忍的,搜索这个问题的解决方式,发现大家也都是粗暴的用synchronize来解决。 

我觉得即使优化也是在加锁的方式上优化,关于加锁的高级用法我没有研究过,所以一直没有太在意过这个问题(不要骂我不思进取不去学习高级用法。。。)。


后来不知道在哪看了什么东东受到了启发,我们可以用队列来解决这个问题啊!!


一个思路就是:创建一个单线程的线程池,所有的数据库操作都用这个线程池来操作


下面是我的demo,非常简单:


public class DBHelper extends SQLiteOpenHelper{


    private static String DBName = "TestDB";

    private static int DBVersion = 1;

    private SQLiteDatabase db;

    private static DBHelper INSTANCE;

    // 不用的时候需要关闭线程池

    private ExecutorService pool;


    private DBHelper(Context context) {

        super(context, DBName, null, DBVersion);

        db = getReadableDatabase();

        // 创建一个单线程池

        pool = Executors.newSingleThreadExecutor();

    }


    // 单例

    public static DBHelper getInstance(Context context){

        if(INSTANCE == null){

            synchronized (DBHelper.class){

                if (INSTANCE == null){

                    INSTANCE = new DBHelper(context.getApplicationContext());

                }

            }

        }

        return INSTANCE;

    }


    @Override

    public void onCreate(SQLiteDatabase db) {


    }


    @Override

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {


    }


    // 模拟一个插入,参数随便写了,返回值和SQLiteDatabase的插入方法一样都是long类型,表示插入的id

    public long insert(final String param){

        Future<Long> submit = pool.submit(new Callable<Long>() {

            @Override

            public Long call() throws Exception {

                // 休眠1秒,模拟耗时

                Thread.sleep(1000);

                Log.e("lzw","插入 param: " + param);

                return 100L;

            }

        });

        long id = -1;

        try {

            // 拿操作结果,这里会阻塞

            id = submit.get();

        } catch (InterruptedException e) {

            e.printStackTrace();

        } catch (ExecutionException e) {

            e.printStackTrace();

        }

        return  id;

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

整个DBHelper是一个单例,在构造里实例化了一个单线程池,insert方法是表示插入,参数随便写了一个,我们通过pool.submit方法把任务提交到了线程池进行执行,返回了一个Future类型的变量, 

后面调用Future的get方法可以拿到返回值,get方法会阻塞,直到执行完call方法里的内容并拿到返回值。关于ExecutorService和Future的使用不是本文重点,大家自行学习。


下面是测试Activity:


public class MainActivity extends AppCompatActivity {


    private TextView tv;

    private DBHelper helper;

    private int param = 0;

    static Handler handler = new Handler();


    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        tv = (TextView) findViewById(R.id.content);

        helper = DBHelper.getInstance(this);

        findViewById(R.id.insert).setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                new Thread(new Runnable() {

                    @Override

                    public void run() {

                        param++;

                        final int param2 = param;

                        final long id = helper.insert("----> " + param2);

                        handler.post(new Runnable() {

                            @Override

                            public void run() {

                                tv.append(id + ":" + param2 + "\n");

                            }

                        });

                    }

                }).start();

            }

        });

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

所有的操作都会逐条执行。 

效果图如下: 



以上就是所有的代码,只是讲了一下思路,用的时候大家根据自己的情况去封装就好了。


其实扩展一下,大家可以自己写一个生产者消费者模型也可以解决这个问题,核心思路和上面的方法都一样,就是一个阻塞队列,需要修改数据库的,把需求添加进队列,DBHelper从队列中不断取并操作数据库。


其实Handler的思路也是这么个套路。


不多说了,下面是代码地址: 

https://github.com/dreamlizhengwei/DatabaseDemo

--------------------- 



标签: 数据库
分享:
评论:
你还没有登录,请先