- 前言
SQLITE
線程安全, 與FMDB多線程安全
是兩回事;
SQLITE
默認(rèn)的線程模式是串行模式
, 是線程安全的
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.
- 測試結(jié)論: 數(shù)據(jù)插入不全
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))];
}];
}
});
- 測試結(jié)論: 數(shù)據(jù)全部插入成功
-
FMDatabaseQueue
與 多線程 與 事務(wù)
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
能實現(xiàn)多線程安全
- 其多線程是在不同子線程把任務(wù)追加
_queue
中
- 真正操作數(shù)據(jù)庫的任務(wù)還是有
_queue
來分配
-
_queue
是一個串行隊列, 且是同步執(zhí)行, 所以所有任務(wù)是一個接一個執(zhí)行, 并不會造成資源搶奪
- (void)inDatabase:(void (^)(FMDatabase *db))block {
dispatch_sync(_queue, ^() {
FMDatabase *db = [self database];
block(db);
FMDBRelease(self);
}