sqlite: Error Code : 5 (SQLITE_BUSY) (database is locked (code 5): , while compiling: PRAGMA journal_mode)
今天遇到了一个很奇怪的问题,登录完成后,程序会莫名crash, 报了下面的错误:
sqlite: Error Code : (SQLITE_BUSY) (database is locked (code ): , while compiling: PRAGMA journal_mode)
经过分析发现是数据库被locked,从而导致在调用
mDatabase = mDBHelper.getWritableDatabase();
时发生了crash, 而android上面同一时间向sqlite里写数据只允许有一个sqlite connection,所以发生了crash, 不过问题根源还是在数据库locked, 那么如何发生locked的呢?
仔细检查后发现:
private synchronized void copyTableFromAnonymousTable() { SQLiteDatabase db = openDatabase(); try { if (db.isOpen()) { db.execSQL("create table if not exists "+ FLIGHT_LOG_TABLE_NAME + "(id integer primary key autoincrement, " + ""+DBConfig.FLYING_LOG_USER_ID+" integer, "+ ""+DBConfig.FLYING_LOG_USER_NAME+" varchar(100), "+ ""+DBConfig.FLYING_LOG_HOME_LAT+" double, "+ ""+DBConfig.FLYING_LOG_HOME_LON+" double, "+ ""+DBConfig.FLYING_LOG_LAST_LAT+" double, "+ ""+DBConfig.FLYING_LOG_LAST_LON+" double, "+ ""+DBConfig.FLYING_LOG_LOCATION+" varchar(250), "+ ""+DBConfig.FLYING_LOG_CITY+" varchar(50), "+ ""+DBConfig.FLYING_LOG_DRONE_TYPE+" integer, "+ ""+DBConfig.FLYING_LOG_DRONE_TYPE_STR+" varchar(100), "+ ""+DBConfig.FLYING_LOG_DRONE_SSID+" varchar(150), "+ ""+DBConfig.FLYING_LOG_DRONE_SN+" varchar(150), "+ ""+DBConfig.FLYING_LOG_TAKEOFF_TIME+" long, "+ ""+DBConfig.FLYING_LOG_LANDING_TIME+" long, "+ ""+DBConfig.FLYING_LOG_DURATION+" long, "+ ""+DBConfig.FLYING_LOG_TAKEOFF_TIME_STR+" varchar(150), "+ ""+DBConfig.FLYING_LOG_RAW_OFFSET+" long, "+ ""+DBConfig.FLYING_LOG_APP_VERSION+" varchar(100), "+ ""+DBConfig.FLYING_LOG_FC_VERSION+" varchar(100), "+ ""+DBConfig.FLYING_LOG_RC_VERSION+" varchar(100), "+ ""+DBConfig.FLYING_LOG_CAM_VERSION+" varchar(100), "+ ""+DBConfig.FLYING_LOG_MAX_HEIGHT+" double, "+ ""+DBConfig.FLYING_LOG_MAX_SPEED+" double, "+ ""+DBConfig.FLYING_LOG_MAX_DISTANCE +" double, "+ ""+DBConfig.FLYING_LOG_TOTAL_MILEAGE+" double, "+ ""+DBConfig.FLYING_LOG_FLIGHT_STATUS+" double, "+ ""+DBConfig.FLYING_LOG_PLATFORM+" varchar(50), "+ ""+DBConfig.FLYING_LOG_EXTEND_DATA1+" varchar(100), "+ ""+DBConfig.FLYING_LOG_EXTEND_DATA2+" varchar(100), "+ ""+DBConfig.FLYING_LOG_EXTEND_DATA3+" varchar(100), "+ ""+DBConfig.FLYING_LOG_EXTEND_DATA4+" varchar(100)" +")"); db.beginTransaction(); db.execSQL("INSERT INTO "+FLIGHT_LOG_TABLE_NAME+" SELECT * FROM "+FLIGHT_DEFAULT_TABLE_NAME+""); db.setTransactionSuccessful(); db.endTransaction(); } } catch (Exception e) { e.printStackTrace(); } finally { closeDatabase(); }
db.execSQL("INSERT INTO "+FLIGHT_LOG_TABLE_NAME+" SELECT * FROM "+FLIGHT_DEFAULT_TABLE_NAME+"");
执行上述SQL语句时是有问题的,而这个问题被try catch 捕获掉了,但是:
db.endTransaction();
却没有被执行!后来将 db.endTransaction(); 移至finally 代码块中发现程序变好了。
以前一直觉得只要记得closeDatabase就好了,却没注意到不 end transaction 也会造成问题,在此记录一下,引以为诫。
关于如何unlock的问题
其实我发现数据库被Locked了之后的第一反应时是如何去unlock。不过很遗憾,我没有在现有的android API里找到类似于数据库lock/unlock的方法。不过android 倒是提供了一个
isDbLockedByCurrentThread() 这样的方法用于检测当前数据库是否有被lock, 网上很多的数据库打开方式都是类似于下列代码:
private synchronized SQLiteDatabase openDatabase() { if (mOpenCounter.incrementAndGet() == 1 || mDatabase == null) { mDatabase = mDBHelper.getWritableDatabase(); } return mDatabase; }
这种方式虽然貌似解决了多个 数据库connection的问题,但是个人以为还是不太完善,像我遇到的这种情况,最终crash就发生在
mDatabase = mDBHelper.getWritableDatabase();
这行代码里。因此个人以为保险起见,可以在上述代码之前添加一个诸如下列的代码:
private synchronized SQLiteDatabase openDatabase() { if (mOpenCounter.incrementAndGet() == 1 || mDatabase == null) { if (mDatabase == null) { mDatabase = mDBHelper.getWritableDatabase(); } else { while (mDatabase.isDbLockedByCurrentThread()) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } mDatabase = mDBHelper.getWritableDatabase(); } } return mDatabase; }
可能会更好点,个人看法。
最新文章
- JIRA FOR LINUX 安装过程
- Git合并分支操作
- 源代码管理工具之SVN
- WCF 内存入口检查失败
- PHP负载均衡
- 【nodejs学习】3.进程管理及异步编程
- java输出空心菱形
- HDU 5898 odd-even number(2016沈阳网络选拔赛 数位DP)
- windows下vue+webpack前端开发环境搭建及nginx部署
- jedis keys和scan操作
- webpack 4.X 与 Vue 2.X结合
- Stack Sorting CodeForces - 911E (思维+单调栈思想)
- highchart应用示例2-上:圆角柱状图,下:多指标曲线图
- java测试感想
- 微信小程序模板中使用循环
- centos7下haproxy1.7的使用与配置
- web office apps 在线预览实践
- MGR Switch Muti-Primary to single_primary
- Zipline Trading Calendars
- centos总结linux下svn安装与使用