FMDB线程安全 事务使用

BOOL result = [db executeUpdate:@"CREATE TABLE IF NOT EXISTS AccountList (money text, useType text, type text, date text, remark text, accountId INTEGER PRIMARY KEY AUTOINCREMENT);”];

其中

accountId INTEGER PRIMARY KEY AUTOINCREMENT

意为创建名为accounId的主变量 类型为int 可以自动增加 删除后不会重新添加该id

FMDB的FMDatabaseQueue是一个串行队列 保证了所有通过该对象添加的block任务是同步的,保证了线程安全。

对于这个队列是否会先判断有无创建表,需要进一步了解—

多数据写入
错误示范:

//    for (int i = 0; i < typeArr.count; i ++) {
//        if (i < typeArr.count - 1) {
//            [[TABDBTool sharedInstance] addType:typeArr[i] success:^{
//
//            } failed:^{
//
//            }];
//        }
//        else {
//            [[TABDBTool sharedInstance] addType:typeArr[i] success:^{
//                [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"tabIsType"];
//                [[NSUserDefaults standardUserDefaults] synchronize];
//                [self getData];
//            } failed:^{
//
//            }];
//        }
//    }

用事务添加会快很多

// 用事务实现批量添加
- (void)addTypeArr:(NSArray *)typeArr success:(TabDbSuccess)success failed:(TabDbFailed)failed
{
    if (typeArr && typeArr.count) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [self.dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
                [db beginTransaction];
                BOOL isRollBack = NO;
                @try
                {
                    for (NSString *type in typeArr) {
                        [db executeUpdateWithFormat:@"INSERT INTO TypeList (type) VALUES (%@);", type];
                    }
                }
                @catch (NSException *exception) {
                    isRollBack = YES;
                    [db rollback];
                }
                @finally {
                    if (!isRollBack) {
                        [db commit];
                        [self resultWithResult:!isRollBack success:success failed:failed];
                    }
                }
            }];
        });
    }
}

// 另一种写法
            __block BOOL flag = NO;
            [self.dbQueue inTransaction:^(FMDatabase * _Nonnull db, BOOL * _Nonnull rollback) {
                @try
                {
                    for (NSString *type in typeArr) {
                        flag = [db executeUpdateWithFormat:@"INSERT INTO TypeList (type) VALUES (%@);", type];
                    }
                }
                @catch (NSException *exception) {
                    *rollback = YES;
                    flag = NO;
                }
                @finally {
                    *rollback = !flag;
                    if (flag) {
                        [self resultWithResult:flag success:success failed:failed];
                    }
                }
            }];

代码示范:
.h

#import 
#import "TABAccountModel.h"
#import "TABTypeModel.h"
#import 

typedef void(^GetDataBlock)(NSMutableArray *array);
typedef void(^TabDbSuccess)(void);
typedef void(^TabDbFailed)(NSString *reason);

@interface TABDBTool : NSObject

@property (nonatomic, strong) FMDatabaseQueue *dbQueue;

+ (TABDBTool *)sharedInstance;


/*
 账单表
 */
- (void)addModel:(TABAccountModel *)model success:(TabDbSuccess)success failed:(TabDbFailed)failed;

- (void)deleteModel:(TABAccountModel *)model success:(TabDbSuccess)success failed:(TabDbFailed)failed;

- (void)deleteWithUseType:(NSString *)type success:(TabDbSuccess)success failed:(TabDbFailed)failed;

- (void)getAllModelWithBlock:(GetDataBlock)block failed:(TabDbFailed)failed;

- (void)getModelListWithUseType:(NSString *)type block:(GetDataBlock)block failed:(TabDbFailed)failed;

- (void)getmodelListWithDate:(NSString *)date block:(GetDataBlock)block failed:(TabDbFailed)failed;

- (void)getmodelListWithUseType:(NSString *)type date:(NSString *)date block:(GetDataBlock)block failed:(TabDbFailed)failed;

/*
 类型表
 */
- (void)addType:(NSString *)type success:(TabDbSuccess)success failed:(TabDbFailed)failed;

- (void)addTypeArr:(NSArray *)typeArr success:(TabDbSuccess)success failed:(TabDbFailed)failed;

- (void)deleteTypeWithTypeId:(TABTypeModel *)typeModel success:(TabDbSuccess)success failed:(TabDbFailed)failed;

- (void)getAllType:(GetDataBlock)block failed:(TabDbFailed)failed;

@end

.m

#import "TABDBTool.h"

@implementation TABDBTool

+ (TABDBTool *)sharedInstance
{
    static TABDBTool *tool = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        tool = [[TABDBTool alloc] init];
    });
    return tool;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        NSString *documentFile = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
        NSString *fileName = [documentFile stringByAppendingPathComponent:@"Account.sqlite"];
        NSLog(@"数据库地址: %@", fileName);
        self.dbQueue = [FMDatabaseQueue databaseQueueWithPath:fileName];
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [self.dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
                BOOL result = [db executeUpdate:@"CREATE TABLE IF NOT EXISTS AccountList (money text, useType text, type text, date text, remark text, accountId INTEGER PRIMARY KEY AUTOINCREMENT);"];
                if (result) {
                    NSLog(@"创建账单表成功");
                }
                else {
                    NSLog(@"创建账单表失败");
                }

                BOOL resultType = [db executeUpdate:@"CREATE TABLE IF NOT EXISTS TypeList (type text, typeId INTEGER PRIMARY KEY AUTOINCREMENT);"];
                if (resultType) {
                    NSLog(@"创建类型表成功");
                }
                else {
                    NSLog(@"创建类型表失败");
                }
            }];
        });
    }
    return self;
}

- (void)addModel:(TABAccountModel *)model success:(TabDbSuccess)success failed:(TabDbFailed)failed
{
    if (model) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [self.dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
                BOOL result = [db executeUpdateWithFormat:@"INSERT INTO AccountList (money, useType, type, date, remark) VALUES (%@, %@, %@, %@, %@);", model.money, model.useType, model.type, model.date, model.remark];
                NSLog(@"保存成功");
                [self resultWithResult:result success:success failed:failed];
            }];
        });
    }
}

- (void)deleteModel:(TABAccountModel *)model success:(TabDbSuccess)success failed:(TabDbFailed)failed
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self.dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
           BOOL result = [db executeUpdateWithFormat:@"delete from AccountList where accountId = %ld;", model.accountId];
            [self resultWithResult:result success:success failed:failed];
        }];
    });
}

- (void)deleteWithUseType:(NSString *)type success:(TabDbSuccess)success failed:(TabDbFailed)failed
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self.dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
            BOOL result = [db executeUpdateWithFormat:@"delete from AccountList where useType = %@;", type];
            [self resultWithResult:result success:success failed:failed];
        }];
    });
}

- (void)updateModel:(TABAccountModel *)model 
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self.dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
            [db executeUpdateWithFormat:@"update AccountList set money = %@ where deviceID = %ld",model.money , model.accountId];
        }];
    });

}

- (void)getAllModelWithBlock:(GetDataBlock)block failed:(TabDbFailed)failed
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [self.dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
                FMResultSet *resultSet = [db executeQuery:@"select * from AccountList"];
                [self getArrayWithResultSet:resultSet block:block failed:failed];
            }];
        });
}

- (void)getModelListWithUseType:(NSString *)type block:(GetDataBlock)block failed:(TabDbFailed)failed
{
    if ([type isEqualToString:@"全部"]) {
        [self getAllModelWithBlock:block failed:failed];
    }
    else {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [self.dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
                FMResultSet *resultSet = [db executeQuery:[NSString stringWithFormat:@"select * from AccountList WHERE useType = '%@'", type]];
                [self getArrayWithResultSet:resultSet block:block failed:failed];
            }];
        });
    }
}

- (void)getmodelListWithDate:(NSString *)date block:(GetDataBlock)block failed:(TabDbFailed)failed
{
    if ([date isEqualToString:@"全部"]) {
        [self getAllModelWithBlock:block failed:failed];
    }
    else {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [self.dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
                FMResultSet *resultSet = [db executeQuery:[NSString stringWithFormat:@"select * from AccountList WHERE date LIKE '%@%%';", date]];
                [self getArrayWithResultSet:resultSet block:block failed:failed];
            }];
        });

    }
}

- (void)getmodelListWithUseType:(NSString *)type date:(NSString *)date block:(GetDataBlock)block failed:(TabDbFailed)failed
{
    if ([type isEqualToString:@"全部"]) {
        [self getmodelListWithDate:date block:block failed:failed];
    }
    else if ([date isEqualToString:@"全部"]) {
        [self getModelListWithUseType:type block:block failed:failed];
    }
    else {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [self.dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
                FMResultSet *resultSet = [db executeQuery:[NSString stringWithFormat:@"select * from AccountList WHERE useType = '%@' and date LIKE '%@%%';", type, date]];
                [self getArrayWithResultSet:resultSet block:block failed:failed];
            }];
        });
    }
}

- (void)resultWithResult:(BOOL)result success:(TabDbSuccess)success failed:(TabDbFailed)failed
{
    if (result) {
        if (success) {
            dispatch_async(dispatch_get_main_queue(), ^{
                success();
            });
        }
    }
    else {
        if (failed) {
            dispatch_async(dispatch_get_main_queue(), ^{
                failed(@"");
            });
        }
    }
}

- (void)getArrayWithResultSet:(FMResultSet *)resultSet block:(GetDataBlock)block failed:(TabDbFailed)failed
{
    NSMutableArray *array = [NSMutableArray array];
    while ([resultSet next]) {
        TABAccountModel *model = [[TABAccountModel alloc] init];
        model.money = [resultSet stringForColumn:@"money"];
        model.useType = [resultSet stringForColumn:@"useType"];
        model.type = [resultSet stringForColumn:@"type"];
        model.remark = [resultSet stringForColumn:@"remark"];
        model.date = [resultSet stringForColumn:@"date"];
        model.accountId = [resultSet longForColumn:@"accountId"];
        [array addObject:model];
    }
    [self sortedArray:array];
    if (array) {
        if (block) {
            dispatch_async(dispatch_get_main_queue(), ^{
                block(array);
            });
        }
    }
    else {
        if (failed) {
            dispatch_async(dispatch_get_main_queue(), ^{
                failed(@"");
            });
        }
    }
}

- (void)sortedArray:(NSMutableArray *)array
{
    [array sortUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
        [formatter setDateFormat:@"yyyy-MM-dd"];
        TABAccountModel *model1 = obj1;
        TABAccountModel *model2 = obj2;
        NSString *str1 = model1.date;
        NSString *str2 = model2.date;
        if (str1 == nil) {
            str1 = @"0000-00-00";
        }
        if (str2 == nil) {
            str2 = @"0000-00-00";
        }
        NSDate *date1 = [formatter dateFromString:str1];
        NSDate *date2 = [formatter dateFromString:str2];
        NSComparisonResult result = [date1 compare:date2];
        if (result == NSOrderedAscending) { // 降序 NSOrderedAscending;
            return YES;
        }
        else {
            return NO;
        }
    }];
}

#pragma mark -- 类型表部分 --
- (void)addType:(NSString *)type success:(TabDbSuccess)success failed:(TabDbFailed)failed
{
    if (type) {

        [self getAllType:^(NSMutableArray *array) {
            BOOL haveType = NO;
            for (TABTypeModel *typeModel in array) {
                if ([typeModel.type isEqualToString:type]) {
                    haveType = YES;
                    break;
                }
            }
            if (!haveType) {
                dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                    [self.dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
                        BOOL result = [db executeUpdateWithFormat:@"INSERT INTO TypeList (type) VALUES (%@);", type];
                        [self resultWithResult:result success:success failed:failed];
                    }];
                });
            }
            else {
                if (failed) {
                    failed(@"数据重复");
                }
            }
        } failed:failed];


    }
}

// 用事务实现批量添加
- (void)addTypeArr:(NSArray *)typeArr success:(TabDbSuccess)success failed:(TabDbFailed)failed
{
    if (typeArr && typeArr.count) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            /*
            [self.dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
                [db beginTransaction];
                BOOL isRollBack = NO;
                @try
                {
                    for (NSString *type in typeArr) {
                        [db executeUpdateWithFormat:@"INSERT INTO TypeList (type) VALUES (%@);", type];
                    }
                }
                @catch (NSException *exception) {
                    isRollBack = YES;
                    [db rollback];
                }
                @finally {
                    if (!isRollBack) {
                        [db commit];
                        [self resultWithResult:!isRollBack success:success failed:failed];
                    }
                }
            }];
            */

            // 另一种写法
            /**/
            __block BOOL flag = NO;
            [self.dbQueue inTransaction:^(FMDatabase * _Nonnull db, BOOL * _Nonnull rollback) {
                @try
                {
                    for (NSString *type in typeArr) {
                        flag = [db executeUpdateWithFormat:@"INSERT INTO TypeList (type) VALUES (%@);", type];
                    }
                }
                @catch (NSException *exception) {
                    *rollback = YES;
                    flag = NO;
                }
                @finally {
                    *rollback = !flag;
                    if (flag) {
                        [self resultWithResult:flag success:success failed:failed];
                    }
                }
            }];
            /**/
        });
    }
}

- (void)deleteTypeWithTypeId:(TABTypeModel *)typeModel success:(TabDbSuccess)success failed:(TabDbFailed)failed
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self.dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
            BOOL result = [db executeUpdateWithFormat:@"delete from TypeList where typeId = %ld;", typeModel.typeId];
            if (result) {
                [self deleteWithUseType:typeModel.type success:success failed:failed];
            }
        }];
    });
}

- (void)getAllType:(GetDataBlock)block failed:(TabDbFailed)failed
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self.dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
            FMResultSet *resultSet = [db executeQuery:@"select * from TypeList"];
            NSMutableArray *array = [NSMutableArray array];
            while ([resultSet next]) {
                TABTypeModel *model = [[TABTypeModel alloc] init];
                model.typeId = [resultSet longForColumn:@"typeId"];
                model.type = [resultSet stringForColumn:@"type"];
                [array addObject:model];
            }
            if (array) {
                if (block) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        block(array);
                    });
                }
            }
            else {
                if (failed) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        failed(@"");
                    });
                }
            }
        }];
    });
}

@end

你可能感兴趣的:(iOS开发)