JQFMDB,操作简单,线程安全,扩展性强

简介: JQFMDBJQFMDB的特性针对于FMDB的二次封装线程安全操作简单, Model和Dictionary直接存储拓展性强支持事务操作不侵入你的任何Model安装JQFMDBCocoapods1. 在 Podfile 中添加 `pod 'JQFMDB'`。
img_bbb95a990ca9ea7b79a3027cb239b825.png
JQFMDB

JQFMDB的特性


  • 针对于FMDB的二次封装
  • 线程安全
  • 操作简单, 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方法获得不同实例, 参数说明同上.

创建表


方式一(用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"}];

增删改查之插入


无论你想插入的是一个model还是dictionary都没问题,都会智能接收并存储
*- (BOOL)jq_insertTable:(NSString )tableName dicOrModel:(id)parameters;
插入一组数据, 也支持model和dictionary混合的数组
**- (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;

`

GitHub


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

img_5833f863421b9267f267b0fb46c3e31d.png
模拟器截图.png

此处应该写点什么的

相关文章
|
11月前
|
SQL Oracle 前端开发
使用MariaDB线程池提高MySQL的扩展性
MySQL的线程池能够有效地解决大量短连接的性能问题,大幅提高MySQL数据库的扩展性。但官方MySQL的线程池在收费的企业版中才有,免费的社区版中没有这个功能,这里介绍MairaDB的线程池。
156 0
|
11月前
|
SQL 运维 Oracle
使用MariaDB线程池提高MySQL的扩展性
MySQL的线程池能够有效地解决大量短连接的性能问题,大幅提高MySQL数据库的扩展性。但官方MySQL的线程池在收费的企业版中才有,免费的社区版中没有这个功能,这里介绍MairaDB的线程池。
174 0
|
17天前
|
Java 数据库 Android开发
【专栏】Kotlin在Android开发中的多线程优化,包括线程池、协程的使用,任务分解、避免阻塞操作以及资源管理
【4月更文挑战第27天】本文探讨了Kotlin在Android开发中的多线程优化,包括线程池、协程的使用,任务分解、避免阻塞操作以及资源管理。通过案例分析展示了网络请求、图像处理和数据库操作的优化实践。同时,文章指出并发编程的挑战,如性能评估、调试及兼容性问题,并强调了多线程优化对提升应用性能的重要性。开发者应持续学习和探索新的优化策略,以适应移动应用市场的竞争需求。
|
5天前
|
Java 数据库
【Java多线程】对线程池的理解并模拟实现线程池
【Java多线程】对线程池的理解并模拟实现线程池
13 1
|
5天前
|
设计模式 消息中间件 安全
【Java多线程】关于多线程的一些案例 —— 单例模式中的饿汉模式和懒汉模式以及阻塞队列
【Java多线程】关于多线程的一些案例 —— 单例模式中的饿汉模式和懒汉模式以及阻塞队列
10 0
|
5天前
|
Java
【Java多线程】分析线程加锁导致的死锁问题以及解决方案
【Java多线程】分析线程加锁导致的死锁问题以及解决方案
15 1
|
5天前
|
存储 缓存 安全
【Java多线程】线程安全问题与解决方案
【Java多线程】线程安全问题与解决方案
15 1
|
5天前
|
Java 调度
【Java多线程】线程中几个常见的属性以及状态
【Java多线程】线程中几个常见的属性以及状态
10 0
|
5天前
|
Java 调度
【Java多线程】对进程与线程的理解
【Java多线程】对进程与线程的理解
12 1
|
6天前
|
存储 安全 Java
【探索Linux】P.21(多线程 | 线程同步 | 条件变量 | 线程安全)
【探索Linux】P.21(多线程 | 线程同步 | 条件变量 | 线程安全)
11 0