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. 2019java第十二周课程总结

    本周主要还是学习图形界面 各种容器使用方法 如下代码: package text10; import java.awt.*; import java.io.File; import javax.swi ...

  2. 深入理解java集合

    集合 Java集合分为三大接口:①Collection ②Map ③Iterator

  3. Golang协程实现流量统计系统(2)

    从进程开始,搜索和理解进程 Google 搜索关键词: C fork example 什么是fork Fork系统调用用于创建一个称为子进程的新进程,该子进程与进行fork()调用的进程(父进程)同时 ...

  4. jquery数组的合并 对象的合并

    直接转自:https://www.cnblogs.com/ooo0/p/7737678.html 1.数组的合并 1.1 concat方法 var a=[1,2,3],b=[4,5,6]; var c ...

  5. 集合(Java总结一)

    一.Queue 一个队列就是一个先入先出(FIFO)的数据结构 1.没有实现的阻塞接口的LinkedList: 实现了java.util.Queue接口和java.util.AbstractQueue ...

  6. 阶段3 2.Spring_06.Spring的新注解_2 spring的新注解-Bean

    下面要解决第二部分的配置问题 这两行一出场,就表示可以通过调用构造函数实例化.因为这都是newInstance 上面的需要加上参数,下面的没有任何参数 下面这俩实现的效果不一样. 下面这个除了会创建对 ...

  7. 2018.04.02 matplotlib 图名,图例,轴标签,轴边界,轴刻度,轴刻度标签

    import numpy as np import pandas as pd import matplotlib.pyplot as plt df = pd.DataFrame(np.random.r ...

  8. 利用Python进行异常值分析实例代码

    利用Python进行异常值分析实例代码 异常值是指样本中的个别值,也称为离群点,其数值明显偏离其余的观测值.常用检测方法3σ原则和箱型图.其中,3σ原则只适用服从正态分布的数据.在3σ原则下,异常值被 ...

  9. 内容与org.apache.axis2.AxisFault: Connection refused: connect 没有太大的关系

    昨天下午  在SVN 检索下来项目   运行的时候遇到一个问题: 然后检查半天访问路径 再运行 居然又出现这个问题 然后又是一顿操作............. 网上找了半天方法 好多人说是  这样的  ...

  10. 【java基础之异常】死了都要try

    目录 1.异常 1.1 异常概念 1.2 异常体系 1.3 异常分类 1.4 异常的产生过程解析 2. 异常的处理 2.1 抛出异常throw 2.2 Objects非空判断 2.3 声明异常thro ...