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

SQLite数据库多线程操作:

 

 

在上面一节中已经讲过FMDB的用法了,接下来讲讲sqlite在都线程中的用法。如果应用中使用了多线程操作数据库,那么就需要使用FMDatabaseQueue来保证线程安全了。 应用中不可在多个线程中共同使用一个FMDatabase对象操作数据库,这样会引起数据库数据混乱。 为了多线程操作数据库安全,多线程FMDatabaseQueue 这个类在多个线程来执行查询和更新时会使用这个类。避免同时访问同一个数据FMDatabaseQueue。首先用一个数据库文件地址来初使化FMDatabaseQueue,然后就可以将一个闭包(block)传入inDatabase方法中。 在闭包中操作数据库,而不直接参与FMDatabase的管理。 

注意点:

1.FMDatabaseQueue是一个串行队列,它不支持串行任务嵌套执行

 

[(FMDatabaseQueue的单例) inDatabase:^(FMDatabase *db) {
        FMResultSet *result = [db executeQuery:[NSStringstringWithFormat:@"select * from BookClassify order by classifyID desc"]];
        
        while ([result next]) {
            //处理result
        }
[(FMDatabaseQueue的单例) inDatabase:^(FMDatabase *db) {
//有问题了
    }];

}];
可以用db再次进行sql操作、不必再inDatabase
2.FMDatabaseQueue不是在次线程中操作、若要次线程操作在外面要包一个

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
    });

 

FMDatabaseQueue保证线程安全基本用法

 

——主要就是在创建数据库的时候,默认已经打开数据库

——随后的很多操作,因为需要在数据库中操作,所以需要利用队列的inDataBase方法调出数据库,在block中执行操作代码。

#import "ViewController.h"
#import "FMDB.h"

@interface ViewController ()
@property(nonatomic,strong) FMDatabaseQueue *queue;
- (IBAction)insert:(id)sender;
- (IBAction)delete:(id)sender;
- (IBAction)update:(id)sender;
- (IBAction)select:(id)sender;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    NSString *filePath=[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"fmdb.sqlite"];
    //创建数据库,并加入到队列中,此时已经默认打开了数据库,无须手动打开,只需要从队列中取出数据库即可
    self.queue=[FMDatabaseQueue databaseQueueWithPath:filePath];
    //取出数据库,这里的db就是数据库,在数据库中创建表
    [self.queue inDatabase:^(FMDatabase *db) {
        //创建表
        BOOL createTableResult=[db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_student (id integer PRIMARY KEY AUTOINCREMENT,name text,age integer)"];
        if (createTableResult) {
            NSLog(@"创建表成功");
        }else{
            NSLog(@"创建表失败");
        }
    }];
}

- (IBAction)insert:(id)sender {
    [self.queue inDatabase:^(FMDatabase *db) {
        for (int index=0; index<50; index++) {
            NSString *s_name=[NSString stringWithFormat:@"Andy%d",arc4random()%100];
            NSNumber *s_age=@(arc4random()%100);
            [db executeUpdate:@"INSERT INTO t_student(name,age) VALUES(?,?)",s_name,s_age];
        }
    }];
}

- (IBAction)delete:(id)sender {
    [self.queue inDatabase:^(FMDatabase *db) {
        [db executeUpdate:@"DELETE FROM t_student WHERE id=?",@1];
    }];
}

- (IBAction)update:(id)sender {
    [self.queue inDatabase:^(FMDatabase *db) {
        [db executeUpdate:@"UPDATE t_student SET name='Jack' WHERE id=?",@2];
    }];
}

- (IBAction)select:(id)sender {
    [self.queue inDatabase:^(FMDatabase *db) {
        //获取结果集,返回参数就是查询结果
        FMResultSet *rs=[db executeQuery:@"SELECT * FROM t_student WHERE age>?",@50];
        while ([rs next]) {
            int ID=[rs intForColumn:@"id"];
            NSString *NAME=[rs stringForColumn:@"name"];
            int AGE=[rs intForColumn:@"age"];
            NSLog(@"%d %@ %d",ID,NAME,AGE);
        }
    }];
}


如果要保证多个操作同时成功或者同时失败,用事务,即把多个操作放在同一个事务中。

 

——FMDB中,拿到数据库直接操作事务,如下:

- (IBAction)update:(id)sender {
    [self.queue inDatabase:^(FMDatabase *db) {
        [db beginTransaction];//开始事务
        [db executeUpdate:@"UPDATE t_student SET name='Jack' WHERE id=?",@2];
        [db executeUpdate:@"UPDATE t_student SET name='Tomy' WHERE id=?",@3];
        //发现情况不对时,主动回滚用下面语句。否则是根据commit结果,如成功就成功,如不成功才回滚
        [db rollback];//主动回滚
        [db executeUpdate:@"UPDATE t_student SET name='Eric' WHERE id=?",@4];
        [db commit];//提交事务
    }];
}

上面因为用的是FMDB封装好的,其实原生的代码是这样的:

[db executeUpdate:@"BEGIN TRANSACTION"];
[db executeUpdate:@"ROLLBACK TRANSACTION"];
[db executeUpdate:@"COMMIT TRANSACTION"];

——FMDB中,也可以直接利用队列进行事务操作,队列中的打开、关闭、回滚事务等都已经被封装好了。

- (IBAction)update:(id)sender {
    [self.queue inDatabase:^(FMDatabase *db) {
        [self.queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
            [db executeUpdate:@"UPDATE t_student SET name='Jack' WHERE id=?",@2];
            [db executeUpdate:@"UPDATE t_student SET name='Tomy' WHERE id=?",@3];
            //发现情况不对时,主动回滚用下面语句。
            *rollback=YES;
            [db executeUpdate:@"UPDATE t_student SET name='Eric' WHERE id=?",@4];
        }];
}

 

 

 

 

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值