数据库
Android数据库设计
- 冗余字段设计,表设计要空出2到3个冗余字段
- 不要过多的关联查询,外键约束不要多了
- 设计要优先考虑易用性 ,容易升级,性能方面主要要通过应用层来掌控
- 适当的分库可以有效避免数据库被锁住。(sqlite的文件锁)
database is locked的原因
- 同时有两个写操作的时候,后执行的只能先等待,如果等待时间超过5秒,就会产生这种错误
- 一个文件正在写入,重复打开数据库操作也会报错
Android DB操作技巧
- 对于经常要使用的DB不需要关闭,一般全局保存一个静态的SQLiteDatabase句柄(Writable的),而且是在Application oncreate 就初始化好.
- 由于Application 没有destroy的回调,这里我们一般会做一个ActivityStack,然后在Activity初始化和destory 时候入栈和出栈来控制界面的显示逻辑,当检测到栈为空的时候就可以认为要退出应用了。
- 能一次取完数据,不要分次取(虽然可能取得数据量有一定优化,但是分次太耗时,尽量交给上层做)
- DataBase is locked,导致数据取不出来。 解决方向有以下几点:
第1点:在获取databse时候加一个锁
第2点:分库,对于相互关联若的数据进行分库处理
第3点:数据库不要关闭,并且尝试分开存writeable 和 readable两个静态的DB
参考文章:
https://segmentfault.com/q/1010000005140824
Android 数据库多线程读写
SQLiteDatabase源码解析
可以知道,insert , update , execSQL 都会调用lock();
query 没有调用lock(),but SQLiteCursor保存了查询条件,但是并没有立即执行查询,而是使用了lazy的策略,在需要时加载部分数据时候依然会SQLiteDatabase.lock()
多线程读写
多线程写
多线程写必须公用一个SqliteHelper,不然会抛出 database is locked的错误
多线程读
多线程读的话可以使用多个SqliteHelper
单写多读
方案: 一个线程写,多个线程同时读,每个线程都用各自SQLiteOpenHelper
问题1:有线程读的时候写数据库会抛出异常 database is locked
原因:
SQLiteOpenHelper.getReadableDatabase() 不见得获得的就是只读SQLiteDatabase
解决方案:
重写getOnlyReadDatabase 来强制只获取只读的Database
问题2:在FIX问题1后在有线程读的时候写数据库仍然会出现database is locked
原因:SQLiteDataBase有个属性 ENABLE_WRITE_AHEAD_LOGGING的属性(默认是关闭的),在关闭时,不允许读,写同时进行(通过锁来保证的);
当打开时,它允许一个写线程与多个读线程同时在一个SQLiteDatabase上起作用。实现原理是写操作其实是在一个单独的文件,不是原数据库文件。所以写在执行时,不会影响读操作,读操作读的是原数据文件,是写操作开始之前的内容。
解决方案:
SQLiteDataBase enableWriteAheadLogging()打开 ENABLE_WRITE_AHEAD_LOGGING属性。
参考文章:
http://www.cnblogs.com/javawebsoa/p/3237018.html
https://blog.csdn.net/qq_25412055/article/details/52414420
数据库调试
第一步通过AS自带的Android monitor 把数据库导出来
第二步通过Sqlite professional
查看数据库的结构可以具体查看到每一张表的详细信息
也可以通过query工具栏,执行基本的命令行操作。