- 前言
SQLITE
线程安全, 与FMDB多线程安全
是两回事;
SQLITE
默认的线程模式是串行模式
, 是线程安全的
FMDatabase
多线程不安全, 单个FMDatabaseQueue
是多线程安全的;
多线程安全测试
NSString *dbPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"tmps.db"];
FMDatabase *db = [FMDatabase databaseWithPath:dbPath];
[db open];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
for (NSInteger i = 0; i < 10; i++) {
[db executeUpdate:@"INSERT INTO t_PetInfo(petNo, age, name, weight, hoster) VALUES(?, ?, ?, ?, ?);", @(i), @(2), @"myPet0", @(15.0), @"derain"];
}
});
dispatch_async(dispatch_get_global_queue(0, 0), ^{
for (NSInteger i = 0; i < 10; i++) {
[db executeUpdate:@"INSERT INTO t_PetInfo(petNo, age, name, weight, hoster) VALUES(?, ?, ?, ?, ?);", @(i), @(2), @"myPet1", @(15.0), @"derain"];
}
});
dispatch_async(dispatch_get_global_queue(0, 0), ^{
for (NSInteger i = 0; i < 10; i++) {
[db executeUpdate:@"INSERT INTO t_PetInfo(petNo, age, name, weight, hoster) VALUES(?, ?, ?, ?, ?);", @(i), @(2), @"myPet2", @(15.0), @"derain"];
}
});
// 打印
2017-08-28 19:37:20.547 ABDataBase[22333:3419905] The FMDatabase <FMDatabase: 0x60000008f910> is currently in use.
2017-08-28 19:37:20.547 ABDataBase[22333:3419908] The FMDatabase <FMDatabase: 0x60000008f910> is currently in use.
2017-08-28 19:37:20.547 ABDataBase[22333:3419905] The FMDatabase <FMDatabase: 0x60000008f910> is currently in use.
2017-08-28 19:37:20.547 ABDataBase[22333:3419908] The FMDatabase <FMDatabase: 0x60000008f910> is currently in use.
2017-08-28 19:37:20.548 ABDataBase[22333:3419905] The FMDatabase <FMDatabase: 0x60000008f910> is currently in use.
dispatch_async(dispatch_get_global_queue(0, 0), ^{
for (NSInteger i = 0; i < 5; i++) {
[self.queue inDatabase:^(FMDatabase *db) {
[db executeUpdate:@"INSERT INTO t_MyTable(name, age, no, class_id) VALUES(?, ?, ?, ?);", [NSString stringWithFormat:@"derain1"], @(20 + arc4random_uniform(10)), @(i), @(arc4random_uniform(10))];
}];
}
});
dispatch_async(dispatch_get_global_queue(0, 0), ^{
for (NSInteger i = 0; i < 5; i++) {
[self.queue inDatabase:^(FMDatabase *db) {
[db executeUpdate:@"INSERT INTO t_MyTable(name, age, no, class_id) VALUES(?, ?, ?, ?);", [NSString stringWithFormat:@"derain2"], @(20 + arc4random_uniform(10)), @(i), @(arc4random_uniform(10))];
}];
}
});
dispatch_async(dispatch_get_global_queue(0, 0), ^{
for (NSInteger i = 0; i < 5; i++) {
[self.queue inDatabase:^(FMDatabase *db) {
[db executeUpdate:@"INSERT INTO t_MyTable(name, age, no, class_id) VALUES(?, ?, ?, ?);", [NSString stringWithFormat:@"derain3"], @(20 + arc4random_uniform(10)), @(i), @(arc4random_uniform(10))];
}];
}
});
-
FMDatabaseQueue
与 多线程 与 事务
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self.queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
for (NSInteger i = 0; i < 5; i++) {
[db executeUpdate:@"INSERT INTO t_MyTable(name, age, no, class_id) VALUES(?, ?, ?, ?);", [NSString stringWithFormat:@"derain0"], @(20 + arc4random_uniform(10)), @(i), @(arc4random_uniform(10))];
}
}];
});
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self.queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
for (NSInteger i = 0; i < 5; i++) {
[db executeUpdate:@"INSERT INTO t_MyTable(name, age, no, class_id) VALUES(?, ?, ?, ?);", [NSString stringWithFormat:@"derain1"], @(20 + arc4random_uniform(10)), @(i), @(arc4random_uniform(10))];
}
}];
});
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self.queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
for (NSInteger i = 0; i < 5; i++) {
[db executeUpdate:@"INSERT INTO t_MyTable(name, age, no, class_id) VALUES(?, ?, ?, ?);", [NSString stringWithFormat:@"derain2"], @(20 + arc4random_uniform(10)), @(i), @(arc4random_uniform(10))];
}
}];
});
- 为什么
FMDatabaseQueue
能实现多线程安全
- 其多线程是在不同子线程把任务追加
_queue
中
- 真正操作数据库的任务还是有
_queue
来分配
-
_queue
是一个串行队列, 且是同步执行, 所以所有任务是一个接一个执行, 并不会造成资源抢夺
- (void)inDatabase:(void (^)(FMDatabase *db))block {
dispatch_sync(_queue, ^() {
FMDatabase *db = [self database];
block(db);
FMDBRelease(self);
}