Skip to content

FMDB的封装,操作简单,线程安全,扩展性强,直接操作model或dictionary

License

Notifications You must be signed in to change notification settings

mengxinyizhui/JQFMDB

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

51 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

JQFMDB

Build Status   MIT Licence   Open Source Love   CocoaPods

为了大家和项目的考虑, 如果使用过程中出现问题或者需要新功能接口提供, 请提一个issue, 需求合理会马上更新, 我每天都会关注 !

JQFMDB的特性

  • 针对于FMDB的二次封装
  • 线程安全
  • 支持事务操作(目前others都仅支持线程安全)
  • 操作简单, Model和Dictionary直接存储
  • 拓展性强
  • 不侵入你的任何Model
  • 不需要实现某些奇怪的协议

截图

模拟器截图

安装JQFMDB

Cocoapods

1. 在 Podfile 中添加 `pod 'JQFMDB'`
2. 执行 `pod install` 或 `pod update`
3. 导入 <JQFMDB/JQFMDB.h>

手动安装

1. 下载 JQFMDB 文件夹内的所有内容。
2. 将 JQFMDB.h和JQFMDB.m 以及FMDB添加(拖放)到你的工程。
3. 导入 "JQFMDB.h"。

使用方法

创建数据库

单例方法
  • + (instancetype)shareDatabase;
  • + (instancetype)shareDatabase:(NSString *)dbName;
  • + (instancetype)shareDatabase:(NSString *)dbName path:(NSString *)dbPath;

单例方法创建数据库, 如果使用shareDatabase创建,则默认在NSDocumentDirectory下创建JQFMDB.sqlite, 但只要使用这三个方法任意一个创建成功, 之后即可使用三个中任意一个方法获得同一个实例,参数可随意或nil dbName 数据库的名称 如: @"Users.sqlite", 如果dbName = nil,则默认dbName=@"JQFMDB.sqlite dbPath 数据库的路径, 如果dbPath = nil, 则路径默认NSDocumentDirectory

// 创建数据库
JQFMDB *db = [JQFMDB shareDatabase];
或
JQFMDB *db = [JQFMDB shareDatabase:@"test.sqlite"];
或
JQFMDB *db = [JQFMDB shareDatabase:@"test.sqlite" path:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]];
init方法
  • - (instancetype)initWithDBName:(NSString *)dbName;
  • - (instancetype)initWithDBName:(NSString *)dbName path:(NSString *)dbPath;

如果操作几个数据库可以init方法获得不同实例, 参数说明同上.

创建表(默认创建主键pkid)

方式一(用Model创建表)
//Person类构成
@interface Person : NSObject

@property (nonatomic, strong)NSString *name;
@property (nonatomic, strong)NSNumber *phoneNum;
@property (nonatomic, strong)NSData *photoData;
@property (nonatomic, assign)NSInteger luckyNum;
@property (nonatomic, assign)BOOL sex;
@property (nonatomic, assign)int age;
@property (nonatomic, assign)float height;  //float类型存入172.12会变成172.19995, 取值时%.2f等于原值172.12
@property (nonatomic, assign)double weight;

// 为了测试除以上类型外, 下面的类型不参与建表
@property (nonatomic, strong)NSDictionary *testDic;
@property (nonatomic, strong)NSArray *testArr;
@property (nonatomic, strong)NSError *testError;
@property (nonatomic, strong)Person *testP;
@end

// 创建表 @"user"=表的名称 表的字段为Person的有效属性
[db jq_createTable:@"user" dicOrModel:[Person class]];
方式二(用字典创建表)
// 创建表 @"user"=表的名称 表的字段为字典的key,类型为字典的value
[db jq_createTable:@"user" dicOrModel:@{@"name":@"TEXT", @"age":@"INTEGER"}];
主键用法
主键是默认自动创建的,名为pkid,如果你需要在你的Model中使用主键, 需要添加主键属性, 属性名必须为pkid
@property (nonatomic, assign)NSInteger pkid;
主键不会参加插入和修改操作

增删改查之插入


无论你想插入的是一个model还是dictionary都没问题,都会智能接收并存储;插入一组数据, 也支持model和dictionary混合的数组

  • - (BOOL)jq_insertTable:(NSString *)tableName dicOrModel:(id)parameters;
  • - (NSArray *)jq_insertTable:(NSString *)tableName dicOrModelArray:(NSArray *)dicOrModelArray;
插入一条数据
Person *person = [[Person alloc] init];
    person.name = @"cleanmonkey";
    person.phoneNum = @(18866668888);
    person.photoData = UIImagePNGRepresentation([UIImage imageNamed:@"bg.jpg"]);
    person.luckyNum = 7;
    person.sex = 0;
    person.age = 26;
    person.height = 172.12;
    person.weight = 120.4555;
// 向user表中插入一条数据
[db jq_insertTable:@"user" dicOrModel:person];
或者你也可以用字典插入部分数据
[db jq_insertTable:@"user" dicOrModel:@{@"name":@"cleanmonkey",@"phoneNum":@(18866668888)}];
插入一组数据
NSMutableArray *mArr = [NSMutableArray arrayWithCapacity:0];
    for (int i = 0; i < 3; i++) {
        Person *person = [[Person alloc] init];
        person.name = [self randomName];
        person.phoneNum = @(18866668888);
        person.photoData = UIImagePNGRepresentation([UIImage imageNamed:@"bg.jpg"]);
        person.luckyNum = 7;
        person.sex = arc4random()%2;
        person.age = 26;
        person.height = 172.12;
        person.weight = 120.4555;
        
        [mArr addObject:person];
    }
// 向user表中插入一组数据
[db jq_insertTable:@"user" dicOrModelArray:mArr];
// 或者也可以是model和dic混合形式的数组
[db jq_insertTable:@"user" dicOrModelArray:@[person, @{@"name":@"cleanmonkey"}, person]]
异步(不阻塞主线程)插入数据, 想来想去还是觉得把异步封装在JQFMDB里不太好
//异步(防止UI卡死)插入一条数据, 也同样可以使用线程安全的方法(在jq_inDatabase的block中插入)
   dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [db jq_insertTable:@"user" dicOrModel:person];
        });

增删改查之删除


根据条件语句删除想要删除的数据;删除表中全部数据

  • - (BOOL)jq_deleteTable:(NSString *)tableName whereFormat:(NSString *)format, ...;
  • - (BOOL)jq_deleteAllDataFromTable:(NSString *)tableName;
删除指定数据
//删除最后一条数据
[db jq_deleteTable:@"user" whereFormat:@"WHERE rowid = (SELECT max(rowid) FROM user)"];
删除表中全部数据
//删除全部数据
[db jq_deleteAllDataFromTable:@"user"];

增删改查之更新


parameters为要更新的数据,可以是model或dictionary, format为条件语句

  • - (BOOL)jq_updateTable:(NSString *)tableName dicOrModel:(id)parameters whereFormat:(NSString *)format, ...;
更新指定数据
//更新最后一条数据 name=testName , dicOrModel的参数也可以是name为testName的person
[db jq_updateTable:@"user" dicOrModel:@{@"name":@"testName"} whereFormat:@"WHERE rowid = (SELECT max(rowid) FROM user)"];
更新所有数据
//把表中所有的name改成godlike
[db jq_updateTable:@"user" dicOrModel:@{@"name":@"godlike"} whereFormat:nil];

增删改查之查找


parameters为查找到数据后每条数据要存入的模型,可以为model或dictionary

  • - (NSArray *)jq_lookupTable:(NSString *)tableName dicOrModel:(id)parameters whereFormat:(NSString *)format, ...;
查找指定数据
////查找name=cleanmonkey的数据
NSArray *personArr = [db jq_lookupTable:@"user" dicOrModel:[Person class] whereFormat:@"where name = 'cleanmonkey'"];
NSLog(@"name=cleanmonkey:%@", personArr);
查找所有表中数据
//查找表中所有数据
NSArray *personArr = [db jq_lookupTable:@"user" dicOrModel:[Person class] whereFormat:nil];
NSLog(@"表中所有数据:%@", personArr);

多线程操作之线程安全


以上操作是非线程安全的, 要想保证线程安全,还是采用FMDB的原型,所有操作都放在下面block中执行, 而block块内代码会被提交到一个队列中,从而保证线程安全, 但要注意的是block不能嵌套使用

/**
 将操作语句放入block中即可保证线程安全, 如:
 Person *p = [[Person alloc] init];
 p.name = @"小李";
 [jqdb jq_inDatabase:^{
 [jqdb jq_insertTable:@"users" dicOrModel:p];
 }];
 */
- (void)jq_inDatabase:(void (^)(void))block;
例:将一系列操作都放在block中会保证线程安全
[db jq_inDatabase:^{
         [db jq_insertTable:@"user" dicOrModel:@{@"name":@"cleanmonkey"}];
         [db jq_lookupTable:@"user" dicOrModel:[Person class] whereFormat:@"where name = 'cleanmonkey'"];
    }];
事务

用A给B转账100元的问题来简单阐述下事务, 首先查询下A的余额,如果>=100元,那么A账户先减去100元, 接着查询B账户的余额, B账户加上100元, 如果说在这之间有任何一个环节出了问题(余额不够, A查询或减去100元操作失败, B查询或加上100元操作失败),则进行回滚操作,相当于回到操作之前的状态,简单说,这就是一个事务操作

事务操作也非常简单, 放在下面block中即可
/**
 Person *p = [[Person alloc] init];
 p.name = @"小李";
 for (int i=0,i < 1000,i++) {
 [jq jq_inTransaction:^(BOOL *rollback) {
 BOOL flag = [jq jq_insertTable:@"users" dicOrModel:p];
 if (!flag) {
 *rollback = YES; //只要有一次不成功,则进行回滚操作
 return;
 }
 }];
 }
 */
// 操作事务的方法
- (void)jq_inTransaction:(void(^)(BOOL *rollback))block;

`

Thanks


Demo(用法注释很详细)和JQFMDB都已经放在了我的GitHub上,更多功能会陆续更新 如果觉得有用,帮忙点个star,十分感谢!

About

FMDB的封装,操作简单,线程安全,扩展性强,直接操作model或dictionary

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Objective-C 97.2%
  • Ruby 2.8%