SQLITE在ANDROID上的一个BUG:
SQLiteCantOpenDatabaseException: unable to open database file
更多内容在这里查看
https://ahangchen.gitbooks.io/windy-afternoon/content
先上log
12-14 19:51:30.346 17770-18098/com.company.product W/System.err: com.company.product.database.sqlite.SQLiteCantOpenDatabaseException: unable to open database file (code 14)
12-14 19:51:30.346 17770-18098/com.company.product W/System.err: at com.company.product.database.sqlite.SQLiteConnection.nativeExecuteForCursorWindow(Native Method)
12-14 19:51:30.346 17770-18098/com.company.product W/System.err: at com.company.product.database.sqlite.SQLiteConnection.executeForCursorWindow(SQLiteConnection.java:913)
12-14 19:51:30.346 17770-18098/com.company.product W/System.err: at com.company.product.database.sqlite.SQLiteSession.executeForCursorWindow(SQLiteSession.java:819)
12-14 19:51:30.346 17770-18098/com.company.product W/System.err: at com.company.product.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:62)
12-14 19:51:30.346 17770-18098/com.company.product W/System.err: at com.company.product.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:159)
12-14 19:51:30.346 17770-18098/com.company.product W/System.err: at com.company.product.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:147)
12-14 19:51:30.346 17770-18098/com.company.product W/System.err: at com.company.product.database.sqlite.AbstractCursor.moveToPosition(AbstractCursor.java:218)
12-14 19:51:30.346 17770-18098/com.company.product W/System.err: at com.company.product.database.sqlite.AbstractCursor.moveToFirst(AbstractCursor.java:258)
先给出结论,
这是sqlite在Android系统上的一个bug,在需要建立索引的sql语句频繁执行时,会发生这个异常。
(如果你是在SQLiteDatabase执行open()时看到的这个exception,那应该是线程冲突的问题,跟这篇文章讲的不是同一个)
根本原因是sqlite临时文件目录不可用。
解决方案是第一次建立连接时设置临时文件目录。
在项目里遇到了这样一个奇怪的crash,长期占据各个版本crash上报榜首,但在开发中一直不能重现。
在许多查DB的代码路径里,都会在moveToFirst(),getCount()等需要执行fillWindow的地方出现这个crash。
* 网络上的解决方案:*
谷歌搜索SQLiteCantOpenDatabaseException,多是一些执行SQLiteDatabase open()时线程冲突的问题,与我们这个问题不同。
跟这个问题相关的回答屈指可数,一直没找到解决方案,最相关的两种回答来自github:
https://github.com/Raizlabs/DBFlow/issues/380
https://github.com/dxopt/OpenFilesLeakTest/blob/master/bugs-show/AbstractCursor.moveToFirst.md
第一个链接与我们的情况相符,但是没有根本的解决方案,只有try – catch
第二个链接讲的是FD泄露导致打不开文件,于是我排查了app中各种泄露的地方,并且写了一个计算文件句柄数的上报工具,发现用户发生此类crash时,FD都不超过256,低于系统对单个进程默认FD数量1024的限制。排除这个可能。
(但有些时候也有可能是由这个问题引发的,可以用StrictMode detectLeak去排查)
于是先尝试在一些可能触发这个Exception的地方try-catch
再分析用户日志,发现try – catch住这个Exception后是可以继续执行一些DB查询的,
于是全都上了try – catch
* 重现路径*
分析用户日志,发现用户的一些共性,由于业务保密限制这里总结一下,共性是DB中数据量很大,并且查询中有大量的子查询。
于是尝试重现这个问题:
在数据量很大的情况下,多次查询就会重现。
可以重现的话就可以开始打log了。
为了在sqlite native层打log,编译sqlite,使用sqlite3_log来输出自己想观察的信息。
首先我们可以看到sqlite的log