今天遇到了一个很奇怪的问题,登录完成后,程序会莫名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;
    }

可能会更好点,个人看法。

sqlite: Error Code : 5 (SQLITE_BUSY) (database is locked (code 5): , while compiling: PRAGMA journal_mode)的更多相关文章

  1. sqlite:多线程操作数据库“database is locked”解决方法(二)

    上一篇博客<sqlite:多线程操作数据库“database is locked”解决方法>通过注册延时函数的方法来处理数据库被锁的问题.此方法固然能解决问题,但是在多个线程向数据库写入大 ...

  2. sqlite:多线程操作数据库“database is locked”解决方法

    1. 使sqlite支持多线程(不确定是否非加不可,暂且加上,以备后患) 可以在编译时/启动时/运行时选择线程模式,参考:http://www.cnblogs.com/liaj/p/4015219.h ...

  3. sqlite遇到database is locked问题的完美解决

    这两天在项目中用大强度大频率的方法测试时遇到sqlite报database is locked的问题,分析下来原因是sqlite对数据库做修改操作时会做(文件)锁使得其它进程同一时间使用时会报该错误( ...

  4. SQLITE报错database is locked的解决办法

    用firedac连接SQLITE数据库,空间tdbedit绑定字段name,如下语句修改其值时报错. procedure TForm1.Button3Click(Sender: TObject);be ...

  5. 解决SQLite database is locked

    前些时候,同事在站点服务端使用SQlite存储一些临时数据,但是在多人并发的时候Sqlite会抛出异常:The database file is locked , database is locked ...

  6. sqlite 报错:database is locked

    在sqlite批量添加数据时,报错:database is locked. 解决办法:将db路径由相对路径设置为绝对路径.

  7. dpkg: error: dpkg status database is locked by another process 解决方法

    使用dpkg -i/apt命令安装,报错: ------------------------------------------------------------- dpkg: error: dpk ...

  8. 解决SQLite中的 database is locked

    前些时候,同事在站点服务端使用SQlite存储一些临时数据,但是在多人并发的时候Sqlite会抛出异常:The database file is locked , database is locked ...

  9. SQLITE 多进程查询出错database is locked

    程序比较简单: 父进程查询数据库A表,没有更新操作 子进程同时查询数据库A表,查询出来的内容更新B表. 两个进程都放到while(1)循环中,速度慢的话就是2S执行一次就没有错,执行的速度快的话就会报 ...

随机推荐

  1. Jenkins卸载方法(Windows/Linux/MacOS)

    注意: 命令行运行的war包或者安装包,都会在命令行上提示了配置文件文件夹.jenkins,卸载时,注意一定要把这些一起删除. 比如Windows下用war包部署的命令行信息如下: 查看原图   如上 ...

  2. 【转】UIAutomator源码分析之启动和运行

    我们可以看到UiAutomator其实就是使用了UiAutomation这个新框架,通过调用AccessibilitService APIs来获取窗口界面控件信息已经注入用户行为事件,那么今天开始我们 ...

  3. HP ALM

    HP ALM 使用经验 使用HP ALM(Application Lifecycle Management)软件有一个多月的时间了,我是从安装,部署,建项,配置,使用,再到问题收集,这个过程过来的.发 ...

  4. 基于kettle8的web端调度监控平台

    发布时间:2018-11-16   技术:spring+springmvc +beetlsql+quartz+kettle8   概述 Kettle调度监控平台(以下简称KS)是一个自主开发的java ...

  5. QQ登录整合/oauth2.0认证-01-申请appkey和appid

    本节需要你申请appkey和appid还有绑定域名的空间 首先 再讲课之前 你需要准备以下东西 到腾讯开发平台中申请 开发者 获得appid 和appkey 这两个东东 这两个东东 就算没审核 也可以 ...

  6. iOS transform解决连续多次旋转缩放,实现图片旋转缩放效果

    一.需求 实现imageView的缩放旋转效果,一般有两种方式: 1.底层加scrollview,利用scrollview的属性实现.(推荐这种,这是我比较后发现的,手势做缩放旋转会有点弊端) 2.利 ...

  7. Python验证码识别处理实例 深度学习大作业

    转载自:http://python.jobbole.com/83945/ http://www.pyimagesearch.com/2014/09/22/getting-started-deep-le ...

  8. cd及目录快速切换

    一.cd   ~ 切换到用户目录 二.cd   - cd - 返回进入当前目录前所在目录 三.pushd.popd.dirs 在Linux的多目录命令提示符中工作是一种痛苦的事情,但以下这些利用lin ...

  9. C# WinForm给Button或其它控件添加快捷键响应

    今天做东西遇到要给按钮添加快捷键.就在这介绍三种添加快捷键的方式. 第一种Alt + *(按钮快捷键) 在大家给button.label.menuStrip等控件设置Text属性时在名字后边加& ...

  10. 【Servlet】java web 文件下载功能实现

    需求:实现一个具有文件下载功能的网页,主要下载压缩包和图片 两种实现方法: 一:通过超链接实现下载 在HTML网页中,通过超链接链接到要下载的文件的地址 <!DOCTYPE html> & ...