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
  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
  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 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 query() {  
  120.   
  121.         List students = new ArrayList();  
  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

    

你可能感兴趣的:(SQLiteException: database is locked异常的解决办法)