FMDB封装了SQLite3的方法,操作数据库变得很简单。

增删改查变简单之后,那么问题来了,如何使用多线程优化对数据库的操作?

这是我们的第一反应估计是dispatch_async().

那么问题又来了,多线程操作如何防止database被lock?

哇哈哈,这个时候就要用到FMDatabaseQueue。

先来了解下FMDatabaseQueue的用法。

先来建个表热热身

  1. NSString* path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/test.db"];
  2. NSLog(@"path = %@",path);
  3. self.dbQueue = [FMDatabaseQueue databaseQueueWithPath:path];
  4. [self.dbQueue inDatabase:^(FMDatabase *db) {
  5. BOOL result =  [db executeUpdate:@"create table if not exists testTable (id integer PRIMARY KEY AUTOINCREMENT, name text)"];
  6. NSLog(@"creare %@",result?@"success":@"fail");
  7. }];

没错,就是这么的简单。

那么再来插入几条数据

  1. [self.dbQueue inDatabase:^(FMDatabase *db) {
  2. for (int i = 0; i < 500; i++) {
  3. [db executeUpdate:@"insert into testTable (name) values(?)",[NSString stringWithFormat:@"name-%d",i]];
  4. }
  5. }];

恩,很帅气有木有。

开启事务,再插入一次

  1. [self.dbQueue inTransaction:^(FMDatabase *db, BOOLBOOL *rollback) {
  2. BOOL result = YES;
  3. for (int i = 500; i < 1000; i++) {
  4. result =  [db executeUpdate:@"insert into testTable (name) values(?)",[NSString stringWithFormat:@"name-%d",i]];
  5. if (!result) {
  6. NSLog(@"break");
  7. *rollback = YES;
  8. break;
  9. }
  10. }
  11. }];

对比下效率:

  1. NSDate* one = [NSDate date];
  2. [self.dbQueue inDatabase:^(FMDatabase *db) {
  3. for (int i = 0; i < 500; i++) {
  4. [db executeUpdate:@"insert into testTable (name) values(?)",[NSString stringWithFormat:@"name-%d",i]];
  5. }
  6. }];
  7. NSDate* two = [NSDate date];
  8. NSTimeInterval first = [two timeIntervalSinceDate:one];
  9. NSLog(@"first = %lf",first);
  10. NSDate* three = [NSDate date];
  11. [self.dbQueue inTransaction:^(FMDatabase *db, BOOLBOOL *rollback) {
  12. BOOL result = YES;
  13. for (int i = 500; i < 1000; i++) {
  14. result =  [db executeUpdate:@"insert into testTable (name) values(?)",[NSString stringWithFormat:@"name-%d",i]];
  15. if (!result) {
  16. NSLog(@"break");
  17. *rollback = YES;
  18. break;
  19. }
  20. }
  21. }];
  22. NSDate* four = [NSDate date];
  23. NSTimeInterval second = [four timeIntervalSinceDate:three];
  24. NSLog(@"second = %lf",second);

输出打印:

  1. 2014-11-18 22:01:57.756 FMDB[7489:230565] path = /Users/zhutc/Library/Developer/CoreSimulator/Devices/9001525C-7201-480E-ADC8-8F77C160A18F/data/Containers/Data/Application/6D0C0AE6-3069-4BEE-A7B9-1161C73540BD/Documents/test.db
  2. 2014-11-18 22:01:57.759 FMDB[7489:230565] creare success
  3. 2014-11-18 22:02:03.029 FMDB[7489:230565] first = 5.270233
  4. 2014-11-18 22:02:03.052 FMDB[7489:230565] second = 0.022609

再看看删除:

  1. NSDate* five = [NSDate date];
  2. [self.dbQueue inDatabase:^(FMDatabase *db) {
  3. [db executeUpdate:@"delete from testTable where id < 500"];
  4. }];
  5. NSDate* six = [NSDate date];
  6. NSTimeInterval third = [six timeIntervalSinceDate:five];
  7. NSLog(@"third = %lf",third);
  8. NSDate* seven = [NSDate date];
  9. [self.dbQueue inTransaction:^(FMDatabase *db, BOOLBOOL *rollback) {
  10. [db executeUpdate:@"delete from testTable where  id >= 500"];
  11. }];
  12. NSDate* eight = [NSDate date];
  13. NSTimeInterval fourth = [eight timeIntervalSinceDate:seven];
  14. NSLog(@"fourth = %lf",fourth);

看看打印:

  1. 2014-11-18 22:02:03.066 FMDB[7489:230565] third = 0.013382
  2. 2014-11-18 22:02:03.080 FMDB[7489:230565] fourth = 0.013715

还是事务高大上!!!

可以看出来:使用事务处理就是将所有任务执行完成以后将结果一次性提交到数据库,如果此过程出现异常则会执行回滚操作,这样节省了大量的重复提交环节所浪费的时间。

多线程在哪里?

看下FMDatabaseQueue的源码,发现了一个串行的queue,而且这个queue是同步调用

这个源码是比较老得,最新版的没下载下来,就拿过来用用。最新版的变动是使用同一个queue,可重入。

  1. - (void)inDatabase:(void (^)(FMDatabase *db))block {
  2. FMDBRetain(self);
  3. dispatch_sync(_queue, ^() {
  4. FMDatabase *db = [self database];
  5. block(db);
  6. if ([db hasOpenResultSets]) {
  7. NSLog(@"Warning: there is at least one open result set around after performing [FMDatabaseQueue inDatabase:]");
  8. }
  9. });
  10. FMDBRelease(self);
  11. }

到这里应该就知道,我们只需要使用dispatch_async,然后配合FMDatabaseQueue。

  1. dispatch_async(dispatch_get_global_queue(0, 0), ^{
  2. [self.dbQueue inTransaction:^(FMDatabase *db, BOOLBOOL *rollback) {
  3. BOOL result = YES;
  4. for (int i = 500; i < 1000; i++) {
  5. result =  [db executeUpdate:@"insert into testTable (name) values(?)",[NSString stringWithFormat:@"name-%d",i]];
  6. if (!result) {
  7. NSLog(@"break");
  8. *rollback = YES;
  9. break;
  10. }
  11. }
  12. }];
  13. });

最新版的FMDB不可以在多个队列中使用同一个FMDatabaseQueue实例,会有问题。至于为毛,等研究透了在补充。哇哈哈!1

FMDB-FMDatabaseQueue的更多相关文章

  1. FMDB多线程读写问题,使用FMDataBaseQueue操作可以解决同时打开一个链接de读写问题

    现在ios里使用的数据库一般都是Sqlite,但是使用Sqlite有个不太好的地方就是在多线程的时候,会出现问题,sqlite只能打开一个读或者写连结.这样的话多线程就会碰到资源占用的问题. 最开始是 ...

  2. 【原】FMDB源码阅读(三)

    [原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...

  3. FMDB的使用方法

    转自:http://blog.devtang.com/blog/2012/04/22/use-fmdb/ 前言 SQLite (http://www.sqlite.org/docs.html) 是一个 ...

  4. FMDB 排它锁

    -------------------------------------基本操作------------------------------------- #import "ViewCon ...

  5. IOS数据存储之FMDB数据库

    前言: 最近几天一直在折腾数据库存储,之前文章(http://www.cnblogs.com/whoislcj/p/5485959.html)介绍了Sqlite 数据库,SQLite是一种小型的轻量级 ...

  6. FMDB第三方框架

    FMDB是同AFN,SDWebImage同样好用的第三方框架,它以OC的方式封装了SQLite的C语言API,使得开发变得简单方便. 附上github链接https://github.com/ccgu ...

  7. FMDB 数据库

    iOS中原生的SQLite API在使用上相当不友好,在使用时,非常不便.于是,就出现了一系列将SQLite API进行封装的库,例如FMDB.PlausibleDatabase.sqlitepers ...

  8. 【原】iOS学习47之第三方-FMDB

    将 CocoaPods 安装后,按照 CocoaPods 的使用说明就可以将 FMDB 第三方集成到工程中,具体请看博客iOS学习46之第三方CocoaPods的安装和使用(通用方法) 1. FMDB ...

  9. FMDB

    一.FMDB简介 1.FMDB简介 iOS中原生的SQLite API在进行数据存储的时候,需要使用C语言中的函数,操作比较繁琐.于是,就出现了一系列将SQLite API进行封装的库,例如FMDB. ...

  10. FMDB浅析

    一.FMDB介绍 FMDB是一种第三方的开源库,FMDB就是对SQLite的API进行了封装,加上了面向对象的思想,让我们不必使用繁琐的C语言API函数,比起直接操作SQLite更加方便. FMDB优 ...

随机推荐

  1. 10、kubernetes之RBAC认证

    一.kubectl proxy # kubectl proxy --port=8080 # curl http://localhost:8080/api/v1/ # curl http://local ...

  2. LeetCode 98. 验证二叉搜索树(Validate Binary Search Tree)

    题目描述 给定一个二叉树,判断其是否是一个有效的二叉搜索树. 假设一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数. 节点的右子树只包含大于当前节点的数. 所有左子树和右子树自身必须也 ...

  3. LeetCode 12. 整数转罗马数字(Integer to Roman)

    题目描述 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M. 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例如, 罗马数字 2 写做 II , ...

  4. Android内存Activity泄露:Handler与Threads

    Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收.也就是说,一个对象不被任何引用所指向,则该对象会在被 ...

  5. leecode 238除自身以外数组的乘积

    class Solution { public: vector<int> productExceptSelf(vector<int>& nums) { //用除法必须要 ...

  6. [doker]ubuntu18安装doker

    ubuntu安装doker很简单,分4个步骤: Step1:更新资源库并安装apt-transprot-https软件包. 在安装Docker前, 首拉取最新的软件资源库 wangju@wangju- ...

  7. <table>表格与jqGrid

    第一次写博客比较生涩.接下来进入正题:...... 普通表格前端的增删改查. <%@ page language="java" contentType="text/ ...

  8. Selenium 2自动化测试实战5(模块调用)

    一.模块调用 1.创建一个目录project,并且在目录下面创建两个文件 project/ 一 pub.py L一 count.py 在pub.py文件中创建add函数. #pub.py def ad ...

  9. 阶段3 2.Spring_07.银行转账案例_3 分析事务的问题并编写ConnectionUtils

    不是没有事务造成的 这样相当于有四个connection 每一个都有自己独立的事物 每一个自己成功就提交事务. 已经提交的就执行结束.没有提交的就报异常 让这些操作使用同一个connection 事物 ...

  10. java:Spring框架3(AOP,SSH集成Demo)

    1.AOP: Spring提供了4种实现AOP的方式: 1.经典的基于代理的AOP 2.@AspectJ注解驱动的切面 3.纯POJO切面 4.注入式AspectJ切面 aop.xml: <?x ...