• 多线程读写

SQLite实质上是将数据写入一个文件,通常情况下,在应用的包名下面都能找到xxx.db的文件,拥有root权限的手机,可以通过adb shell,看到data/data/packagename/databases/xxx.db这样的文件。
我们可以得知SQLite是文件级别的锁:多个线程可以同时读,但是同时只能有一个线程写。Android提供了SqliteOpenHelper类,加入Java的锁机制以便调用。
如果多线程同时读写(这里的指不同的线程用使用的是不同的Helper实例),后面的就会遇到android.database.sqlite.SQLiteException: database is locked这样的异常。
对于这样的问题,解决的办法就是keep single sqlite connection,保持单个SqliteOpenHelper实例,同时对所有数据库操作的方法添加synchronized关键字。
如下所示:

public class DatabaseHelper extends SQLiteOpenHelper {public static final String TAG = "DatabaseHelper";private static final String DB_NAME = "practice.db";private static final int DB_VERSION = 1;private Context mContext;private static DatabaseHelper mInstance;private DatabaseHelper(Context context) {super(context, DB_NAME, null, DB_VERSION);}public synchronized static DatabaseHelper getInstance(Context context) {if (mInstance == null) {mInstance = new DatabaseHelper(context);}return mInstance;}@Overridepublic void onCreate(SQLiteDatabase db) {// TODO Auto-generated method stub
}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {// TODO Auto-generated method stub
}
public synchronized void queryMethod() {SQLiteDatabase readableDatabase = getReadableDatabase();//read operation
        }public void updateMethod() {SQLiteDatabase writableDatabase = getWritableDatabase();//update operation
        }
}

View Code

Android为我们提供了SqliteOpenHelper类,我们可以通过getWritableDatabase或者getReadableDatabase拿到SQLiteDatabase对象,然后执行相关方法。这2个方法名称容易给人误解,我也在很长的一段时间内想当然的认为getReadabeDatabase就是获取一个只读的数据库,可以获取很多次,多个线程同时读,用完就关闭,实际上getReadableDatabase先以读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,当打开失败后会继续尝试以只读方式打开数据库。

public synchronized SQLiteDatabase getReadableDatabase() {if (mDatabase != null && mDatabase.isOpen()) {return mDatabase;  // The database is already open for business
        }if (mIsInitializing) {throw new IllegalStateException("getReadableDatabase called recursively");}try {return getWritableDatabase();} catch (SQLiteException e) {if (mName == null) throw e;  // Can't open a temp database read-only!Log.e(TAG, "Couldn't open " + mName + " for writing (will try read-only):", e);}SQLiteDatabase db = null;try {mIsInitializing = true;String path = mContext.getDatabasePath(mName).getPath();db = SQLiteDatabase.openDatabase(path, mFactory, SQLiteDatabase.OPEN_READONLY);if (db.getVersion() != mNewVersion) {throw new SQLiteException("Can't upgrade read-only database from version " +db.getVersion() + " to " + mNewVersion + ": " + path);}onOpen(db);Log.w(TAG, "Opened " + mName + " in read-only mode");mDatabase = db;return mDatabase;} finally {mIsInitializing = false;if (db != null && db != mDatabase) db.close();}}

View Code

在多线程中,如果第一个线程先调用getWritableDatabase,后面线程再次调用,或者第一个线程先调用 getReadableDatabase,后面的线程调用getWritableDatabase,那么后面的这个方法是会失败的,因为数据库文件打开后 会加锁,必须等前面的关闭后后面的调用才能正常执行,正是因为这个原因,可以1 Write+Many Read(有可能产生冲突,因为第一个getReadableDatabase有可能先于getWritableDatabase执行,导致后面的失 败),也可以Many Read,但是不可能Many Write。所以使用单例加上同步的数据库操作方法,就不会出现死锁的问题,这部分例子请参照附件,多线程可以运行的很好,另外关于Sqlite database locking collisions example,网上有很不错的一个例子,可以这里去下载。

其实我觉得理论上可以修改getReadableDatabase方法,打开的数据库都是Read Only的,这样就能同时1 Write+Many Read,只不过要保证打开之前,数据库要创建或者升级好,这样读操作就不会互斥写操作,效率相对更高。
关于数据库关闭的问题,在下面好的习惯中会专门说明。

  • 事务

接触过数据库的人,对事务这个概念一定不陌生,它是原子性的,要么执行成功,执行一半失败后会回滚,这样就能保证数据的完整性。SQLiteDatabase也提供了Transaction的相关方法,常见用法:

db.beginTransaction();try {...db.setTransactionSuccessful();} finally {db.endTransaction();}

使用事务对于批量更新有极大的好处,因为单次更新会频繁的调用数据库。

  • 除此之外要有几点要注意

1.关闭Cursor
Cursor如果不关闭,虽然不会导致出错,但是Log中会有错误提示,还是严谨点,Activity中有startManagingCursor的方法,Activity会在生命周期结束时关闭这些Cursor,其他地方,我们则需要用完关闭,以前需要Cursor的Adapter则需要在changeCursor时判断关闭old cursor,在Activity的onDestory方法中关闭cursor。
2.关闭DatabaseHelper
在上述单例Helper例子中,其实一直没有关闭数据库,但是我们阅读getReadabeDatabase和getWritableDatabas的方法,他们会关闭Old SQLiteDatabase的,我们只需要在Application的onTerminal方法中关闭即可,这样也能避免多线程中,一个线程关闭了数据库,导致其他线程使用的时候失败的问题。
实质上,数据库是一个文件引用,单例模式下,不关闭也不会出现问题,让它保持随单例的生命周期关闭就好了。
3.在循环外面获取ColumnIndex,如果表中列不是很多,每次查询又返回所有列的话,可以将列的index定义到TABLE_COLUMNS中去,这样每次获取指定列数据的话,就不用去查找index了。
4.数据库存放的数据类型
Android提供了多种数据存储的方法,文件,数据库,SharePreference,网络等,要根据情况选择合适的方式,不要把什么东西都往数据库中塞。
下面的几种情况就不适合放到数据库中:
1)图片等二进制数据:如果是图片的话,可以将文件名称或者路径保存到数据库中,真正的文件可以作为缓存文件保存在文件系统中。
2)临时数据:定位获取到的Location,登录的Session等。
3)日志数据:可以写入文件中,通常是log_xxxx.txt。

转载于:https://www.cnblogs.com/kkong/p/3555282.html

多线程操作SQLite注意事项相关推荐

  1. FMDatabaseQueue 数据库多线程操作、事务处理

    SQLite数据库多线程操作: 在上面一节中已经讲过FMDB的用法了,接下来讲讲sqlite在都线程中的用法.如果应用中使用了多线程操作数据库,那么就需要使用FMDatabaseQueue来保证线程安 ...

  2. MFC不能多线程操作控件的原因

    对于大多数mfc对象,请不要在线程间传递它们,不管是栈上的还是堆上的!原因如下:   mfc的大多数类不是线程安全的,调用传入对象的成员函数可能不会报错,但是未必能达到程序预定的功能!   mfc与界 ...

  3. java多线程 注意事项_多线程使用及注意事项

    1.并行和并发的区别 2.多线程(高并发编程)的优点 3.多线程程序需要注意事项 4.线程的启动与安全中止 5.怎么安全中止线程(interrupt()) 并行和并发的区别: 一个是同时执行,一个是交 ...

  4. Qt中操作SQLite数据库

    0.前言 SQLite是一款开源.轻量级.跨平台的数据库,无需server,无需安装和管理配置.它的设计目标是嵌入式的,所以很适合小型应用,也是Qt应用开发种常用的一种数据库. 1.驱动 Qt SQL ...

  5. android查询mysql并显示_Android操作SQLite数据库(增、删、改、查、分页等)及ListView显示数据的方法详解...

    本文实例讲述了Android操作SQLite数据库(增.删.改.查.分页等)及ListView显示数据的方法.分享给大家供大家参考,具体如下: 由于刚接触android开发,故此想把学到的基础知识记录 ...

  6. Poco库使用:操作SQLite数据库

    Sqlite是在工程项目中使用比较多的小型数据库.由于其非常小巧且占用资源低,深受开发者喜欢.这里就介绍一下如何通过Poco框架操作SQLite数据库.这里假设你已经完整编译了Poco库,如果还没有编 ...

  7. 一行 Python 实现并行化 -- 日常多线程操作的新思路 - 左手键盘,右手书 - SegmentFault...

    一行 Python 实现并行化 -- 日常多线程操作的新思路 - 左手键盘,右手书 - SegmentFault

  8. android 开发使用adb操作sqlite

    android 开发使用adb操作sqlite. 1.启动模拟器或连接android实体机 2.在命令行输入:adb shell 3.进入目录:data/data/应用程序包名/databases/ ...

  9. python sqlalchemy操作SQLite

    日期转时间: from sqlalchemy import Column, Integer, String, Float, Date date = Column(Date) data="20 ...

最新文章

  1. 尚硅谷学习笔记-节点的常用属性和方法
  2. LINUX相关的镜像源网站大全,个人收集完整版!
  3. [原创]linux简单之美(二)
  4. I/0口输入输出实验 流水灯程序 P0、P1、P2、P3口作为输出口,连接八只发光二极管,编写程序,使发光二极管从左至右循环点亮。
  5. 2021零售行业营销自由白皮书
  6. Mac下iTerm2的ls输出如何显示文件件颜色呢?
  7. Python调用安卓手机相机接口进行拍照
  8. mysql load data infile 上传数据 不显示_第22问:我有带外键的表,你有数据么?
  9. 三种文本特征提取(TF-IDF/Word2Vec/CountVectorizer)
  10. Qt+VS2019+OpenCV 使用问题 - Cound not find “QT“
  11. 战胜25名医生:AI真能成为医疗界的“擂主”?
  12. WCF+SQL Server 2008 明源售楼系统项目解析
  13. 凸集(Convex sets)
  14. The server encountered an internal error () that prevented it from fulfilling this request
  15. SpringBoot 2.3 新特性之优雅停机
  16. 哪些seo搜索技巧你不会用?
  17. 我的物联网项目(二十九) 线上前期运营
  18. 《你好,安怡》热播,AI觉醒,奇点临近?
  19. [解决网络出现“正在连接”的问题]
  20. H3C WX2510h无线控制器如何网关式部署无线网络

热门文章

  1. python 中空NULL的表示
  2. e1载波把32个信道按_什么是Wi-Fi 6?这12个问题为你讲清楚
  3. 推荐系统思维导图——第二章
  4. 算!力!羊!毛!5000核时计算资源终于开放使用了!
  5. 昔年浅谈电商服务业务应如何推广
  6. kafka数据 落盘_终于知道Kafka为什么这么快了!
  7. php视图最佳实践,PHP 的最佳实践
  8. 使用@onetomany取不到值_SpringCloud微服务架构篇2:微服务基础—SpringBoot使用
  9. 图片居中裁剪_魔镜,魔镜,谁最美丽!利用PS图层混合模式打造图片幻觉效果
  10. python3 常见命令