一、代码示例

1.需要先导入FMDB框架和头文件,由于该框架依赖于libsqlite库,所以还应该导入该库。

2.代码如下:

 1 //
2 // YYViewController.m
3 // 05-FMDB数据库队列
4 //
5 // Created by apple on 14-7-28.
6 // Copyright (c) 2014年 wendingding. All rights reserved.
7 //
8
9 #import "YYViewController.h"
10 #import "FMDB.h"
11
12 @interface YYViewController ()
13 @property(nonatomic,strong)FMDatabaseQueue *queue;
14 @end
15
16 @implementation YYViewController
17
18 - (void)viewDidLoad
19 {
20 [super viewDidLoad];
21
22 //1.获得数据库文件的路径
23 NSString *doc=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
24 NSString *fileName=[doc stringByAppendingPathComponent:@"person.sqlite"];
25
26 //2.获得数据库队列
27 FMDatabaseQueue *queue=[FMDatabaseQueue databaseQueueWithPath:fileName];
28 // FMDatabase *db=[FMDatabase databaseWithPath:fileName];
29
30 //3.打开数据库
31 [queue inDatabase:^(FMDatabase *db) {
32 BOOL result=[db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_person (id integer PRIMARY KEY AUTOINCREMENT, name text NOT NULL, age integer NOT NULL);"];
33 if (result) {
34 NSLog(@"创表成功");
35 }else
36 {
37 NSLog(@"创表失败");
38 }
39 }];
40 self.queue=queue;
41
42 }
43
44 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
45 {
46 //插入数据
47 // [self.queue inDatabase:^(FMDatabase *db) {
48 // [db executeUpdate:@"INSERT INTO t_person (name, age) VALUES (?, ?);",@"wendingding", @22];
49 // }];
50
51 //查询数据
52 [self.queue inDatabase:^(FMDatabase *db) {
53 // 1.执行查询语句
54 FMResultSet *resultSet = [db executeQuery:@"SELECT * FROM t_person"];
55
56 // 2.遍历结果
57 while ([resultSet next]) {
58 int ID = [resultSet intForColumn:@"id"];
59 NSString *name = [resultSet stringForColumn:@"name"];
60 int age = [resultSet intForColumn:@"age"];
61 NSLog(@"%d %@ %d", ID, name, age);
62 }
63 }];
64
65 }
66
67 @end

先插入数据,之后查询结果,打印如下:

3.代码说明

有了一个队列对象,它的内部自动就拥有一个数据库对象,且数据库的操作是线程安全的。
 
二、事务
事务,没有事务的话会出现问题。
举例:银行的例子
 
张三和李四账户都有1000块钱,如果张三要转账给李四,需要执行两条SQL语句,考虑到安全性,要求这两条语句要么全部执行成功,要么全部执行失败。
事务:把多条语句放到同一个事务中,要么全部成功,要么全部失败(如果中途出现问题,那么会自动回滚)。事务的执行具有原子性。
  事务代码处理:
  把多条语句添加到一个事务中去执行:
1    //插入数据
2 [self.queue inDatabase:^(FMDatabase *db) {
3 [db beginTransaction];
4 [db executeUpdate:@"INSERT INTO t_person (name, age) VALUES (?, ?);",@"wendingding", @22];
5 [db executeUpdate:@"INSERT INTO t_person (name, age) VALUES (?, ?);",@"wendingding", @23];
6 [db executeUpdate:@"INSERT INTO t_person (name, age) VALUES (?, ?);",@"wendingding", @24];
7 [db executeUpdate:@"INSERT INTO t_person (name, age) VALUES (?, ?);",@"wendingding", @25];
8 [db commit];
9 }];

如果中途出现问题,那么会自动回滚(重新开始),也可以选择手动回滚。

 1     //插入数据
2 [self.queue inDatabase:^(FMDatabase *db) {
3 [db beginTransaction];
4 [db executeUpdate:@"INSERT INTO t_person (name, age) VALUES (?, ?);",@"wendingding", @22];
5 [db executeUpdate:@"INSERT INTO t_person (name, age) VALUES (?, ?);",@"wendingding", @23];
6 [db executeUpdate:@"INSERT INTO t_person (name, age) VALUES (?, ?);",@"wendingding", @24];
7 [db rollback];
8 [db executeUpdate:@"INSERT INTO t_person (name, age) VALUES (?, ?);",@"wendingding", @25];
9 [db commit];
10 }];

上面的代码。前三条插入语句是作废的。

事务处理的另一种方式:

1    [self.queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
2 [db executeUpdate:@"INSERT INTO t_person (name, age) VALUES (?, ?);",@"wendingding", @22];
3 [db executeUpdate:@"INSERT INTO t_person (name, age) VALUES (?, ?);",@"wendingding", @23];
4 [db executeUpdate:@"INSERT INTO t_person (name, age) VALUES (?, ?);",@"wendingding", @24];
5 }];

具体可以参考FMDB官方文档:

使用FMDatabaseQueue 及线程安全
在多个线程中同时使用一个FMDatabase实例是不明智的。现在你可以为每个线程创建一个FMDatabase对象。 不要让多个线程分享同一个实例,它无法在多个线程中同时使用。所以,不要初始化FMDatabase对象,然后在多个线程中使用。请使用 FMDatabaseQueue,它是你的朋友而且会帮助你。以下是使用方法:
 
首先创建队列。
  1. FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath];
这样使用(简单的使用,非事务)
  1. [queue   inDatabase:^(FMDatabase *db) {
  2. [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]];
  3. [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]];
  4. [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]];
  5. FMResultSet *rs = [db executeQuery:@"select * from foo"];
  6. while([rs next]) {
  7. }
  8. }];
像这样,轻松地把简单任务包装到事务里:
  1. [queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
  2. [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]];
  3. [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]];
  4. [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]];
  5. if (whoopsSomethingWrongHappened) {    //有什么错误发生的话,回滚
  6. *rollback = YES; return;
  7. }
  8. // etc…
  9. [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:4]];
  10. }];
 
 FMDatabaseQueue  后台会建立系列化的G-C-D队列,并执行你传给G-C-D队列的块。这意味着 你从多线程同时调用调用方法,GDC也会按它接收的块的顺序来执行。
 

whoopsSomethingWrongHappened是什么鬼?????看一下下面的demo

#pragma mark - 数据存储文件的路径

- (NSString *)dbPathTest {

NSString *string = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];

NSString *stringPath = [string stringByAppendingPathComponent:@"test.sqlite"];

NSLog(@"%@",stringPath);

return stringPath;

}

#pragma mark - 多线程操作数据库时,事务的处理方式

- (void)threadTransaction {

//创建队列

FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:[self dbPathTest]];

__block BOOL whoopsSomethingWrongHappened = true;

//把任务包装到事务里

[queue  inTransaction:^(FMDatabase *db, BOOL *rollback) {

whoopsSomethingWrongHappened &= [db executeUpdate:@"insert into myTable values(?)",[NSNumber numberWithInt:1]];

whoopsSomethingWrongHappened &= [db executeUpdate:@"insert into myTable values(?)",[NSNumber numberWithInt:2]];

whoopsSomethingWrongHappened &= [db executeUpdate:@"insert into myTabl values(?)",[NSNumber numberWithInt:3]];

//如果有错误 返回

if(!whoopsSomethingWrongHappened) {

*rollback = YES;

return;

}

NSLog(@"hello,yoowei");

}];

}

还可以看一下其他的demo中的写法:

- (void)saveChangesInBackground:(void (^)())complete {

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:self.schema.storage];

        [queue  inTransaction:^(FMDatabase *db, BOOL *rollback) {

            @try {

                for (FMDTObject *entry in self.dataArray) {

                    NSArray *array = [self getObjectValues:entry];

                    NSString *statement = nil;

                    if (self.relpace) {

                        statement = self.schema.statementReplace;

                    } else {

                        statement = self.schema.statementInsert;

                    }

                    [db executeUpdate:statement withArgumentsInArray:array];

                }

            }

            @catch (NSException *exception) {

                *rollback = YES;

            }

[self.dataArray removeAllObjects];

if (complete) {

complete();

}

}];

});

}

- (void)threadNoTransaction {

FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:[self dbPathTest]];

[queue inDatabase:^(FMDatabase *db) {

[db beginTransaction];

BOOL isRollBack = NO;

@try {

for (int i = 0; i<5; i++) {

NSString *roomID= [[NSString alloc] initWithFormat:@"roomid_%d",i];

NSString *sql= @"insert into myTable values(?)";

BOOL a = [db executeUpdate:sql,roomID];

if (!a) {

NSLog(@"插入失败1");

}

}

}

@catch (NSException *exception) {

isRollBack = YES;

[db rollback];

}

@finally {

if (!isRollBack) {

[db commit];

}

}

}];

}

参考链接:

http://www.cnblogs.com/wendingding/p/3873874.html

https://github.com/ccgus/fmdb

数据存储_FMDB数据库队列的更多相关文章

  1. Django中从本地上传excel文件并将数据存储到数据库

    Django中从本地上传excel文件并将数据存储到数据库 一.前端界面 <div class="page-container"> <form action=&q ...

  2. Android开发--数据存储之数据库操作

    简介: SQLite 的介绍: SQLite数据库属于文本型的数据库,它是以文本的形式来保存的.Android提供了对 SQLite 数据库的完全支持,应用程序中的任何类都可以通过名称来访问任何的数据 ...

  3. Hive 表操作(HIVE的数据存储、数据库、表、分区、分桶)

    1.Hive的数据存储 Hive的数据存储基于Hadoop HDFS Hive没有专门的数据存储格式 存储结构主要包括:数据库.文件.表.试图 Hive默认可以直接加载文本文件(TextFile),还 ...

  4. iOS应用数据存储2-SQLite3数据库

          SQLite3 SQLite3是一款开源的嵌入式关系型数据库,可移植性好,易使用,内存开销小. SQLite3是无类型的,意味着你可以保存任何类型的数据到任意表的任意字段中. SQLite ...

  5. Android数据存储——SQLite数据库(模板)

    本篇整合Android使用数据库,要保存一个实体类的样本. 首先看一下数据库语句: ORM:关系对象映射 添加数据: ContentValues values = new ContentValues( ...

  6. 数据存储_FMDB

    一.简单说明 1.什么是FMDB FMDB是iOS平台的SQLite数据库框架 FMDB以OC的方式封装了SQLite的C语言API 2.FMDB的优点 使用起来更加面向对象,省去了很多麻烦.冗余的C ...

  7. Python数据存储 — MySQL数据库操作

    本地安装MySQL 调试环境python3.6,调试python操作mysql数据库,首先要在本地或服务器安装mysql数据库. 安装参考:https://mp.csdn.net/postedit/8 ...

  8. Springboot将数据存储到数据库当中

    1.从前端获取数据,同时存储到use当中 public String login(HttpServletRequest request) { User user = new User(); user. ...

  9. Python - 数据存储与数据库简介

随机推荐

  1. AEAI CRM_v1.5.2升级说明,开源客户关系管理系统

    1.升级说明 本次AEAI CRM升级内容主要是针对数通畅联推出AEAI ECP企业云联平台而升级的,其中对AEAI CRM的各模块进行扩展,同时增加了移动门户版功能及为AEAI ECP提供数据服务接 ...

  2. 开启基本数据结构和算法之路--初识Graphviz

    在我的Linux刀耕开荒阶段,就想开始重拾C,利用C实现常用的基本数据结构和算法,而数据结构和算法的掌握的熟练程度正是程序的初学者与职业程序员的分水岭. 那么怎么开启这一段历程呢? 按照软件工程的思想 ...

  3. VS插件开发 - 登录身份验证

    [附加] 很多朋友问那个VS背景怎么弄的,我刚刚已经抽时间把制作步骤发出来了: 请参见<VS插件开发 - 个性化VS IDE编辑器,瞬间 高 大 上>. 最近一直在忙着一些事情,一直没有发 ...

  4. java简单模拟生产者消费者问题

    本文来自:http://www.cnblogs.com/happyPawpaw/archive/2013/01/18/2865957.html 引言 生产者和消费者问题是线程模型中的经典问题:生产者和 ...

  5. Windows 7 在资源管理器中显示软件快捷方式

    该方法是利用资源管理器中储存网络位置的文件夹实现的, 不需要修改注册表. 效果如图: 操作方法: 在资源管理器中打开路径 "%appdata%\Microsoft\Windows\Netwo ...

  6. JCIP chap3 share objects

    "同步"确保了操作的原子性执行,但它还有其它重要的方面:memory visibility.我们不但要确保当一个线程在使用一个对象的时候,其它线程不能修改这个对象,而且还要保证该线 ...

  7. 【转】XenServer的架构之Xenopsd组件架构与运行机制

    一.Xenopsd概述 Xenopsd是XenServer的虚拟机管理器. Xenopsd负责:启动,停止,暂停,恢复,迁移虚拟机:热插拔虚拟磁盘(VBD):热插拔虚拟网卡(VIF):热插拔虚拟PCI ...

  8. javascript的ajax

    AJAX 一 AJAX预备知识:json进阶 1.1 什么是JSON? JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.JSON是用字符串来表示Javas ...

  9. Centos7安装PHP7

    安装依赖 yum updateyum install gcc-c++ libxml2 libxml2-devel openssl openssl-devel bzip2 bzip2-devel lib ...

  10. C#简单的对象交互

    在对象的世界里,一切皆为对象;对象与对象相互独立,互不干涉,但在一定外力的作用下对象开始共同努力 对象交互的实例 电视机大家都有吧,依照万物皆对象的思维模式来看,电视机可以是一个类,然后电视机有一些基 ...