Sqlite Database是一个比较稳定轻量的小型数据库,不像是mysql、oracle等数据库同样具备单独的服务进程。基于sqlite的读写都是读写原始的磁盘文件,也就是说sqlite的操做彻底是磁盘的IO操做。SQLite操做存在必定的异常状况,在客户端也难以监控,在用户基数比较大的状况下,每每对极少数的用户的影响也是致命的。了解sqlite便于咱们规范的去使用它。html
一般的异常状况都包含在如下状况:mysql
官方的文档也有介绍到android
How To Corrupt An SQLite Database File sql
鉴于操做系统和Sqlite bug等不可控方面咱们更多须要作到能准确的监控,如内存不足,相似于微信的作法就是监控到内存不足,弹出提示框告知用户去清理内存。下面就来探讨下因为操做不当引发的异常。数据库
android.database.sqlite.SQLiteDatabaseLockedException DB引擎在执行job的时候发现获取不到数据库的锁就会抛出这个异常。数据库锁用于防止多线程同时写入数据从而致使DB损坏。因此通常发生在多线程的事务操做上。针对同一个事务代码段,若是一个事务还没有结束提交,另一个线程便开始介入执行就会致使冲突抛出此异常。微信
因此出现上述异常,请检查你的代码。建议的操做是:多线程
系统文件锁问题SQLite依赖于底层的文件系统对文件锁的实现。SQLite 默认锁是协同锁。假设有A、B线程同时访问数据库并写入数据。这个时候来个C线程不是使用SQLite API的方式来操做数据的话(如直接的IO操做),那么数据库锁就会被自动取消,A、B线程在没有锁保护的状态同时操做db就可能致使DB的损坏。oracle
建议:性能
批量写入比较大的数据咱们可能想要更快的速度,网上不少会建议你设置PRAGMA synchronous=OFF, Android对应的设置方式就是:mDatabase.execSQL("PRAGMA synchronous=OFF"); 等同于在说:我期待更快的写入速度,磁盘驱动器为了达到目标,就耍了个小聪明,忽略开始SQLite的同步操做,先通知到系统我写入完了。实际上不必定数据彻底写入了,假如这个时候出现了断电等意外,就会致使真实数据写入失败从而引起DB损坏。优化
建议:
尽可能不要设置PRAGMA synchronous=OFF 数据比较大的写入等操做从sql语句优化和性能的优化入手。
不少较为复杂的应用可能一个应用程序不止有一个数据库。这里列举一个场景,应用包含两个DB。 DatabaseA:预置数据的数据库,已经设计好表并提早插入了数据。不须要跟随应用动态的去建立DB。用户第一次安装的时候把准备好的DB经过IO的方式拷贝到应用包路径下面的databases路径提供给应用访问,此DB通常只用读,不多或者彻底不写入数据,是静态的。 DatabaseB: 跟随应用的安装和升级动态的建立和升级,做为应用数据的持久化方式之一。读写操做均比较频繁。
DababaseA会在应用的启动的时候IO迁移拷贝。DatabaseB动态Create后处处可能都有使用到(包括启动)
Danger 1:文件覆盖
DatabaseB的DBOpenHelperB正在读写DatabaseA的表,同时DatabaseA正在被IO线程拷贝写入文件覆盖。DBOpenHelperB创建链接可能依然是旧的数据库,读写天然也是到旧的数据库。部分文件系统甚至引起IO拷贝被中断。
Danger 2:交叉读写
通常有多个DB会对应多个DBOpenHelper进行读写,如过DBOpenHelper作了跨DB的读写,就会致使重复的DB Open或Close,影响到了其余DBOpenHelper的正常读写。直接的致使锁异常或者DB损坏等问题。
多DB建议:
综上多数状况都是代码上操做不当引起的问题,了解好原理才能对症下药,避开危险区。
补充: 减小多进程或多线程操做,尽量单线程写; 减小事务操做,减少事务复杂度。