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. Linux TCP套接字选项 之 SO_REUSEADDR && SO_REUSEPORT

    说明 前面从stackoverflow上找了一篇讲这两个选项的文章,文章内容很长,读到最后对Linux中的这两个选项还是有些迷茫,所以重新写一篇文章来做一个总结: 本文只总结TCP单播部分,并且只讨论 ...

  2. 有关C#写一个WindowsService的两篇文章

    1.http://blog.csdn.net/yysyangyangyangshan/article/details/10515035 上面的这篇文章一共两段,第二段讲的是使用代码来安装发布这个Win ...

  3. shell编程常用命令

    Linux中常用的命令 #nl  filename   使用nl命令打印文件内容并显示行号 #sed   '/nw/,$d'   filename     使用sed命令删除匹配nw至最后一行的内容 ...

  4. ddms 和 traceview 的区别?

    ddms 原意是:davik debug monitor service.简单的说 ddms 是一个程序执行查看器,在里面可以看见线程和堆栈等信息,traceView 是程序性能分析器.tracevi ...

  5. git pull 覆盖本地代码

    在使用Git的过程中,有些时候我们只想要git服务器中的最新版本的项目,对于本地的项目中修改不做任何理会,就需要用到Git pull的强制覆盖,具体代码如下: $ git fetch --all $ ...

  6. mxml 嵌入as代码出错,缺少 CDATA

    如果<mx:Script> 中有大于小于符号,代码必须包含在<![CDATA[ 之中,否则会报错

  7. 通过wscript运行的JS脚本,如何引入另一个JS文件

    链接: https://helloacm.com/include-external-files-in-vbscriptjscript-wsh/ 代码示例: function Include(jsFil ...

  8. Windows系统Git Bash Sock5代理

    git config --global https.proxy http://127.0.0.1:1080 git config --global https.proxy https://127.0. ...

  9. shell历史命令

    1.每分钟备份历史命令 制定计划任务:每分钟执行备份历史命令的脚本 注意:要用python写计划任务脚本,因为用shell脚本写的计划任务总是不执行 先写脚本: [root@master ~]# ca ...

  10. harbor扩容

    1.参照文档  https://k8s.abcdocker.com/kubernetes_harbor.html 2.设置连接 ln到其他文件目录下