SQLiteException: database is locked异常的解决办法

原理:文件数据库sqlite,同一时刻允许多个进程/线程读,但同一时刻只允许一个线程写。在操行写操作时,数据库文件被琐定,此时任何其他读/写操作都被阻塞,如果阻塞超过5秒钟(默认是5秒,能过重新编译sqlite可以修改超时时间),就报"database is locked"错误。

所以,在操作sqlite时,应该即时关闭连接;打开连接后,尽量减少非常费时的操作。

 

1. 方法

在页面中用到了ViewPager控件,ViewPager中的内容分别是两个ListView,两个ListView的数据都来自本地数据库(先从网络下载数据,然后更新本地数据库),在实际的使用过程中发现会出现SQLiteDatabaseLockedException: database is locked的问题。

经网上搜索资料,发现是读写数据库时存在的同步问题,所以采用单例+同步锁的方法,并且在每次数据库操作后都关闭数据库,经测试后发现没有在出现上述问题。

以下是两个主类

DBHelper.java(这个类用来管理数据库)

 

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class DBHelper extends SQLiteOpenHelper {  
  2.   
  3.     private final String TAG = this.getClass().getSimpleName();  
  4.       
  5.     public final static String DATABASE_NAME = "test.db";  
  6.     public final static String TABLE = "table";  
  7.     public final static int DATABASE_VERSION = 2;  
  8.   
  9.     public DBHelper(Context context) {  
  10.         super(context, DATABASE_NAME, null, DATABASE_VERSION);  
  11.     }  
  12.   
  13.     private static DBHelper mInstance;  
  14.   
  15.     public synchronized static DBHelper getInstance(Context context) {  
  16.         if (mInstance == null) {  
  17.             mInstance = new DBHelper(context);  
  18.         }  
  19.         return mInstance;  
  20.     };  
  21.   
  22.     @Override  
  23.     public void onCreate(SQLiteDatabase db) {  
  24.         try {  
  25.             db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE  
  26.                     + "(id INTEGER PRIMARY KEY ,data BLOB)");  
  27.         } catch (SQLiteException e) {  
  28.             e.printStackTrace();  
  29.         }  
  30.     }  
  31.   
  32.     @Override  
  33.     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {    
  34.           
  35.         // 删除原来的数据表  
  36.         db.execSQL("DROP TABLE IF EXISTS " + TABLE);  
  37.         // 重新创建  
  38.         onCreate(db);  
  39.     }  
  40.   
  41.     public static byte[] objectToBytes(Object obj) throws Exception {  
  42.   
  43.         ByteArrayOutputStream out = new ByteArrayOutputStream();  
  44.         ObjectOutputStream sOut = new ObjectOutputStream(out);  
  45.         sOut.writeObject(obj);  
  46.         sOut.flush();  
  47.         byte[] bytes = out.toByteArray();  
  48.         return bytes;  
  49.     }  
  50.   
  51.     public static Object bytesToObject(byte[] bytes) throws Exception {  
  52.   
  53.         ByteArrayInputStream in = new ByteArrayInputStream(bytes);  
  54.         ObjectInputStream sIn = new ObjectInputStream(in);  
  55.         return sIn.readObject();  
  56.     }  
  57. }  


DBStudentManager类(这里可以定义自己的管理类)

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class DBStudentManager {  
  2.   
  3.     private DBHelper helper;  
  4.     private SQLiteDatabase db;  
  5.   
  6.     public DBStudentManager(Context context) {  
  7.         helper = DBHelper.getInstance(context);  
  8.         db = helper.getWritableDatabase();  
  9.     }  
  10.   
  11.     // 插入  
  12.     private void insert(Student student) {  
  13.   
  14.         synchronized (helper) {  
  15.             // 看数据库是否关闭  
  16.             if (!db.isOpen()) {  
  17.                 db = helper.getWritableDatabase();  
  18.             }  
  19.             // 开始事务  
  20.             db.beginTransaction();  
  21.             try {  
  22.                 db.execSQL(  
  23.                         "INSERT INTO " + DBHelper.TABLE + " VALUES(?,?)",  
  24.                         new Object[] { student.mID,  
  25.                                 DBHelper.objectToBytes(student) });  
  26.                 db.setTransactionSuccessful(); // 设置事务成功完成  
  27.             } catch (SQLException e) {  
  28.                 e.printStackTrace();  
  29.             } catch (Exception e) {  
  30.                 e.printStackTrace();  
  31.             } finally {  
  32.                 db.endTransaction();  
  33.                 db.close();  
  34.             }  
  35.         }  
  36.     }  
  37.   
  38.     // 更新  
  39.     private void update(Student student) {  
  40.   
  41.         synchronized (helper) {  
  42.             if (!db.isOpen()) {  
  43.                 db = helper.getWritableDatabase();  
  44.             }  
  45.             db.beginTransaction();  
  46.             try {  
  47.                 db.execSQL("UPDATE " + DBHelper.TABLE  
  48.                         + "SET data = ? WHERE id = ?",  
  49.                         new Object[] { DBHelper.objectToBytes(student),  
  50.                                 student.mID });  
  51.                 db.setTransactionSuccessful(); // 设置事务成功完成  
  52.             } catch (SQLException e) {  
  53.                 e.printStackTrace();  
  54.             } catch (Exception e) {  
  55.                 e.printStackTrace();  
  56.             } finally {  
  57.                 db.endTransaction();  
  58.                 db.close();  
  59.             }  
  60.         }  
  61.     }  
  62.   
  63.     // 同步  
  64.     public void synchronous(List<Student> students) {  
  65.         if (students == null) {  
  66.             return;  
  67.         }  
  68.         for (Student student : students) {  
  69.             if (query(student.mID) == null) {  
  70.                 insert(student);  
  71.             } else {  
  72.                 update(student);  
  73.             }  
  74.         }  
  75.     }  
  76.   
  77.     // 删除指定数据  
  78.     public void delete(String id) {  
  79.   
  80.         synchronized (helper) {  
  81.             if (!db.isOpen()) {  
  82.                 db = helper.getWritableDatabase();  
  83.             }  
  84.             db.beginTransaction();  
  85.             try {  
  86.                 db.execSQL("DELETE FROM " + DBHelper.TABLE + " WHERE id = ? ",  
  87.                         new String[] { id });  
  88.                 db.setTransactionSuccessful();  
  89.             } catch (Exception e) {  
  90.                 e.printStackTrace();  
  91.             } finally {  
  92.                 db.endTransaction();  
  93.                 db.close();  
  94.             }  
  95.         }  
  96.     }  
  97.   
  98.     // 删除所有数据  
  99.     public void delete() {  
  100.   
  101.         synchronized (helper) {  
  102.             if (!db.isOpen()) {  
  103.                 db = helper.getWritableDatabase();  
  104.             }  
  105.             db.beginTransaction();  
  106.             try {  
  107.                 db.execSQL("DELETE * FROM " + DBHelper.TABLE);  
  108.                 db.setTransactionSuccessful();  
  109.             } catch (Exception e) {  
  110.                 e.printStackTrace();  
  111.             } finally {  
  112.                 db.endTransaction();  
  113.                 db.close();  
  114.             }  
  115.         }  
  116.     }  
  117.   
  118.     // 查找所有的Students  
  119.     public List<Student> query() {  
  120.   
  121.         List<Student> students = new ArrayList<Student>();  
  122.         synchronized (helper) {  
  123.             if (!db.isOpen()) {  
  124.                 db = helper.getWritableDatabase();  
  125.             }  
  126.             Cursor c = queryTheCursor();  
  127.             Student student = null;  
  128.             try {  
  129.                 while (c.moveToNext()) {  
  130.   
  131.                     byte[] bytes = c.getBlob((c.getColumnIndex("data")));  
  132.                     student = (Student) DBHelper.bytesToObject(bytes);  
  133.                     students.add(student);  
  134.                 }  
  135.             } catch (Exception e) {  
  136.                 e.printStackTrace();  
  137.             } finally {  
  138.                 c.close();  
  139.             }  
  140.         }  
  141.         return students;  
  142.     }  
  143.   
  144.     // 查找指定ID的Student  
  145.     public Student query(String id) {  
  146.   
  147.         Student student = null;  
  148.         synchronized (helper) {  
  149.             if (!db.isOpen()) {  
  150.                 helper.getWritableDatabase();  
  151.             }  
  152.             Cursor c = queryTheCursor(id);  
  153.             try {  
  154.                 while (c.moveToNext()) {  
  155.   
  156.                     byte[] bytes = c.getBlob((c.getColumnIndex("data")));  
  157.                     student = (Student) DBHelper.bytesToObject(bytes);  
  158.                     break;  
  159.                 }  
  160.             } catch (Exception e) {  
  161.                 e.printStackTrace();  
  162.             } finally {  
  163.                 c.close();  
  164.             }  
  165.         }  
  166.         return student;  
  167.     }  
  168.   
  169.     // 获取游标  
  170.     public Cursor queryTheCursor(String id) {  
  171.         Cursor c = db.rawQuery("SELECT FROM " + DBHelper.TABLE  
  172.                 + " WHERE id = ?"new String[] { id });  
  173.         return c;  
  174.     }  
  175.   
  176.     // 获取游标  
  177.     public Cursor queryTheCursor() {  
  178.         Cursor c = db.rawQuery("SELECT * FROM " + DBHelper.TABLE);  
  179.         return c;  
  180.     }  
  181.   
  182.     class Student {  
  183.   
  184.         String mID;  
  185.         String mName;  
  186.         int mAge;  
  187.     }  
  188. }  


 2. 方法

遇到这个问题,有几种可能,我在下面详细的列出来,方便大家在遇到的时候查看

· 多线程访问造成的数据库锁定。

如A线程在访问当前的数据库,这时候B线程也需要访问数据库,这样在B线程中,就会有类似以上的异常产生,我们需要将提供数据库访问的方法设置成同步的,防止异步调用时出现问题,如:

public static synchronized DBConnection getConnection(String connectionName) throws Exception { String pathFile = getPath() + connectionName;// 转换目录data下 return new DBConnection(SQLiteDatabase.openDatabase(pathFile, null, SQLiteDatabase.OPEN_READWRITE)); }

使用synchronized 关键字来修饰获取数据库连接的方法,或者使用 isDbLockedByOtherThreads方法判断数据库是否被锁住了,然后等待一定的时间再进行访问。
·sqlite自身的问题
有时我们会在调试程序的时候发现Log控制台频繁的出现上述异常,而在运行程序的时候就没有这个问题,这种现象我在调试ResultSet时也会出现,查资料找原因是因为sqlite数据不完全是线程安全的,导致在一些地方会莫名其妙的出问题,如果遇到这样的情况,那只能不要将断点打到数据库连接的地方了。

3. 方法

如果多线程同时读写(这里的指不同的线程用使用的是不同的Helper实例),后面的就会遇到android.database.sqlite.SQLiteException: database is locked这样的异常。
对于这样的问题,解决的办法就是keep single sqlite connection保持单个SqliteOpenHelper实例,同时对所有数据库操作的方法添加synchronized关键字。

完美解决sqlite的 database locked 或者是 error 5: database locked 问题


转自:1. http://blog.csdn.net/sdsxleon/article/details/18259973

           2.http://blog.csdn.net/lizzy115/article/details/8016066

           3.http://www.eoeandroid.com/forum.php?mod=viewthread&tid=333473

   4.http://blog.csdn.net/tianyitianyi1/article/details/39453359

    

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 当出现"sqlite database is locked"的错误时,意味着有其他进程或线程正在访问或修改数据库文件,并且已经对其进行了独占锁定。SQLite数据库使用一种称为独占性写入锁(exclusive write lock)的算法来处理并发访问。 造成数据库被锁定的常见情况有以下几种: 1. 在一个连接中同时启动多个事务并尝试修改数据库。SQLite数据库一次只能有一个写入事务,其他事务必须等待直到当前事务完成。 2. 在一个连接中同时启动多个写操作(如插入、更新或删除)线程,并尝试同时修改数据库。 3. 一个事务在长时间运行(例如,处理大量数据)而没有释放锁定,导致其他连接无法获取锁定。 为解决"sqlite database is locked"错误,可以采取以下几种方法: 1. 确保在一个连接中只有一个事务在操作数据库:在一个事务执行完毕前,不要同时启动其他事务。 2. 在使用写操作之前,检查数据库是否已经被锁定。可以使用SQLite的函数`sqlite3_busy_timeout()`来设置等待锁定的超时时间,以避免长时间阻塞。 3. 优化事务操作:将事务分解为多个较小的事务,或者使用批量插入、更新和删除操作来减少每个操作的次数。 4. 如果可能的话,通过使用缓存机制或调整读写操作的时间,尽量减少数据库的并发读写操作。 最后,需要注意的是,使用SQLite时要正确处理并发访问以及锁定,以保证数据库的一致性和可用性。 ### 回答2: "sqlite database is locked" 是SQLite数据库中的一个错误信息,表示当前的数据库文件被其他进程锁定,无法执行请求的操作。 当多个进程或线程同时访问同一个SQLite数据库文件时,会出现锁定现象。这是为了确保数据的完整性和一致性,避免多个进程同时修改数据库而导致冲突和损坏。 出现"sqlite database is locked"错误的情况有以下几个可能原因: 1. 并发访问:如果多个进程或线程同时试图访问数据库,其中一个进程可能会独占数据库文件资源,而其他进程则被阻塞并显示此错误。 2. 锁定问题:一个进程已经开始了一个事务并锁定了数据库文件,而另一个进程尝试访问相同的数据库文件,发生冲突。 3. 操作冲突:当一个进程正在执行一个写操作时,另一个进程也尝试执行写操作,会产生冲突。SQLite不支持并发写操作,因此会产生"sqlite database is locked"错误。 解决这个问题的方法有: 1. 等待:可以通过等待一段时间,让占用数据库资源的进程完成操作,然后再次尝试访问数据库。 2. 优化并发操作:通过合理地规划数据库操作顺序、使用合适的事务管理和锁定机制,以减少并发访问时的冲突机会。 3. 重新设计应用程序:如果并发访问需求较高,可以重新设计应用程序架构,使用数据库服务器或其他分布式数据库解决方案,来更好地支持并发操作。 总之,"sqlite database is locked"错误表示数据库文件被其他进程锁定,我们需要合理规划并发访问,使用合适的解决方法来解决这个问题。 ### 回答3: SQLite数据库被锁是一个常见的错误,通常是由于多个进程或线程同时尝试对同一个数据库进行读写操作而导致的。当一个进程或线程正在执行一个事务并且没有释放锁时,其他进程或线程将无法访问该数据库,从而导致数据库被锁。 解决这个问题的方法有几种: 1. 等待:可以尝试在一段时间内等待数据库锁的释放,然后重试执行操作。这可能需要根据具体情况调整等待时长。 2. 优化访问模式:检查代码中的访问模式,并确保每个进程或线程都按照正确的顺序访问数据库,以避免出现冲突。 3. 使用事务:事务可以保证对数据库的原子性操作,最大限度地减少锁定时间。确保在适当的时候开始和提交事务。 4. 关闭连接:在某些情况下,关闭所有尝试访问数据库的连接,并重新打开连接可能有助于解决锁定问题。 总的来说,解决SQLite数据库被锁问题的关键在于识别并处理潜在的并发访问冲突,采取适当的措施以确保线程安全并最大限度地减少对数据库的访问冲突。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值