iOS下FMDB的多线程操作(一)

2024-06-13 06:32
文章标签 操作 多线程 ios fmdb

本文主要是介绍iOS下FMDB的多线程操作(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

iOS中一些时间比较长的操作都应该放在子线程中,以避免UI的卡顿。而sqlite 是非线程安全的,故在多线程中不能共用同一个数据库连接,否则会导致EXC_BAD_ACCESS。所以我们可以在子线程中创建一个新的db连接(新建一个db对象),然后再操作数据库。

如果选择FMDB,除了以上所说的方式外,还可以利用FMDatabaseQueue来解决多线程问题。

关于FMDB的使用网上教程比较多,内容基本都是与唐巧的这篇http://www.devtang.com/blog/2012/04/22/use-fmdb/差不多

这里记录一下多线程下的使用。

方式一:采用每次新建db的方式

db路径我是写了一个方法

+ (NSString *)getDBPath
{NSString* docsdir = [NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES) lastObject];NSFileManager *filemanage = [NSFileManager defaultManager];docsdir = [docsdir stringByAppendingPathComponent:@"FMDBDemo"];BOOL isDir;BOOL exit =[filemanage fileExistsAtPath:docsdir isDirectory:&isDir];if (!exit || !isDir) {[filemanage createDirectoryAtPath:docsdir withIntermediateDirectories:YES attributes:nil error:nil];}NSString *dbpath = [docsdir stringByAppendingPathComponent:@"myDB.sqlite"];return dbpath;
}

1、创建数据库表

/** 创建表 */
+ (BOOL)createUserTableByDB
{FMDatabase *db = [FMDatabase databaseWithPath:[self getDBPath]];if (![db open]) {NSLog(@"数据库打开失败!");return NO;}NSString *sql = @"CREATE TABLE IF NOT EXISTS User(ID INTEGER PRIMARY KEY, name TEXT, age INTEGER, ID_No TEXT);";BOOL res = [db executeUpdate:sql];if (res) {NSLog(@"创建表格成功");}else {NSLog(@"创建表格失败");}return res;
}
2、插入数据

插入数据,我分了两种情形,一种是单条插入,一种是利用事务(利用事务插入多条时,时间会快很多,而且有任何一条插入失败,则不会提交到数据库)

/** 保存单个对象 */
- (BOOL)saveByDB
{FMDatabase *db = [FMDatabase databaseWithPath:[User getDBPath]];if (![db open]) {NSLog(@"数据库打开失败!");return NO;}NSString *sql = [NSString stringWithFormat:@"INSERT INTO User(name, age, ID_No) VALUES ('%@', '%d', '%@');", self.name, self.age, self.ID_no];BOOL res = [db executeUpdate:sql];[db close];if (res) {NSLog(@"插入数据成功");}else {NSLog(@"插入数据失败");}return res;
}/** 批量保存用户对象 */
+ (BOOL)saveObjectsByDB:(NSArray *)array
{FMDatabase *db = [FMDatabase databaseWithPath:[self getDBPath]];if (![db open]) {NSLog(@"数据库打开失败!");return NO;}[db beginTransaction];BOOL isRollBack = NO;@try {for (User *user in array) {NSString *sql = [NSString stringWithFormat:@"INSERT INTO User(name, age, ID_No) VALUES ('%@', '%d', '%@');", user.name, user.age, user.ID_no];BOOL res = [db executeUpdate:sql];if (!res) {NSLog(@"db事务插入失败");}else {NSLog(@"db事务插入成功");}}}@catch (NSException *exception) {isRollBack = YES;[db rollback];}@finally {if (!isRollBack) {[db commit];}}[db close];return !isRollBack;
}

更新与删除也分两种情形,与插入类似。

3、更新数据

/** 更新单个对象 */
- (BOOL)updateByDB
{FMDatabase *db = [FMDatabase databaseWithPath:[User getDBPath]];if (![db open]) {NSLog(@"数据库打开失败!");return NO;}NSString *sql = [NSString stringWithFormat:@"UPDATE User SET name = '%@',age = '%d',ID_no = '%@' WHERE ID = '%d';", self.name, self.age, self.ID_no, self.ID];BOOL res = [db executeUpdate:sql];[db close];if (res) {NSLog(@"插入数据成功");}else {NSLog(@"插入数据失败");}return res;
}/** 批量更新用户对象*/
+ (BOOL)updateObjectsByDB:(NSArray *)array
{FMDatabase *db = [FMDatabase databaseWithPath:[User getDBPath]];if (![db open]) {NSLog(@"数据库打开失败!");return NO;}[db beginTransaction];BOOL isRollBack = NO;@try {for (User *user in array) {NSString *sql = [NSString stringWithFormat:@"UPDATE User SET name = '%@',age = '%d',ID_no = '%@' WHERE ID = '%d';", user.name, user.age, user.ID_no, user.ID];BOOL res = [db executeUpdate:sql];if (!res) {NSLog(@"db事务更新失败");}else {NSLog(@"db事务更新成功");}}}@catch (NSException *exception) {isRollBack = YES;[db rollback];}@finally {if (!isRollBack) {[db commit];}}[db close];return !isRollBack;
}
4、删除数据
/** 删除单个对象 */
- (BOOL)deleteObjectByDB
{FMDatabase *db = [FMDatabase databaseWithPath:[User getDBPath]];if (![db open]) {NSLog(@"数据库打开失败!");return NO;}NSString *sql = [NSString stringWithFormat:@"DELETE FROM User WHERE ID = '%d'",self.ID];BOOL res = [db executeUpdate:sql];[db close];if (res) {NSLog(@"删除数据成功");}else {NSLog(@"删除数据失败");}return res;
}/** 批量删除用户对象 */
+ (BOOL)deleteObjectsByDB:(NSArray *)array
{FMDatabase *db = [FMDatabase databaseWithPath:[self getDBPath]];if (![db open]) {NSLog(@"数据库打开失败!");return NO;}[db beginTransaction];BOOL isRollBack = NO;@try {for (User *user in array) {NSString *sql = [NSString stringWithFormat:@"DELETE FROM User WHERE ID = '%d'",user.ID];BOOL res = [db executeUpdate:sql];if (!res) {NSLog(@"db事务删除失败");}else {NSLog(@"db事务删除成功");}}}@catch (NSException *exception) {isRollBack = YES;[db rollback];}@finally {if (!isRollBack) {[db commit];}}[db close];return !isRollBack;
}

5、查询数据

查询就比较简单了。

/** 查询全部用户 */
+ (NSArray *)findAllByDB
{FMDatabase *db = [FMDatabase databaseWithPath:[self getDBPath]];if (![db open]) {NSLog(@"数据库打开失败!");return nil;}NSMutableArray *users = [[NSMutableArray alloc] init];NSString *sql = @"SELECT * FROM User";FMResultSet *resultSet = [db executeQuery:sql];while ([resultSet next]) {User *user = [[User alloc] init];user.ID = [resultSet intForColumn:@"ID"];user.name = [resultSet stringForColumn:@"name"];user.age = [resultSet intForColumn:@"age"];user.ID_no = [resultSet stringForColumn:@"ID_no"];[users addObject:user];[user release];}NSLog(@"查询全部成功");return [users autorelease];
}/** 查找某个用户 */
+ (instancetype)findFirstBySqlByDB:(NSString *)sql
{User *user = nil;NSArray *users = [self findBySqlByDB:sql];if (users.count > 0) {user = [users firstObject];}return user;
}/** 查找用户 */
+ (NSArray *)findBySqlByDB:(NSString *)sql
{FMDatabase *db = [FMDatabase databaseWithPath:[self getDBPath]];if (![db open]) {NSLog(@"数据库打开失败!");return nil;}NSMutableArray *users = [[NSMutableArray alloc] init];NSString *select = @"SELECT * FROM User ";if (sql) {select = [select stringByAppendingString:sql];}FMResultSet *resultSet = [db executeQuery:select];while ([resultSet next]) {User *user = [[User alloc] init];user.ID = [resultSet intForColumn:@"ID"];user.name = [resultSet stringForColumn:@"name"];user.age = [resultSet intForColumn:@"age"];user.ID_no = [resultSet stringForColumn:@"ID_no"];[users addObject:user];[user release];}NSLog(@"条件查询成功");return [users autorelease];
}

而多线程下的调用方式是这样的,其中上面的所有方法都是在对象类User中。

/** 用db插入User数据*/
- (IBAction)dbInsertData:(id)sender {//多线程插入数据for (int i = 0; i < 5; i++) {dispatch_async(dispatch_get_global_queue(0, 0), ^{User *user = [[User alloc] init];user.name = @"dbName一";user.ID_no = [NSString stringWithFormat:@"%d",55555+i];user.age = 555+i;[user saveByDB];});}//利用事务插入数据dispatch_async(dispatch_get_global_queue(0, 0), ^{NSMutableArray *array = [NSMutableArray array];for (int i = 0; i < 5; i++) {User *user = [[User alloc] init];user.name = @"db事务";user.ID_no = [NSString stringWithFormat:@"%d",66666+i];user.age = 66+i;[array addObject:user];[user release];}[User saveObjectsByDB:array];});
}


这篇关于iOS下FMDB的多线程操作(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1056533

相关文章

SQL中JOIN操作的条件使用总结与实践

《SQL中JOIN操作的条件使用总结与实践》在SQL查询中,JOIN操作是多表关联的核心工具,本文将从原理,场景和最佳实践三个方面总结JOIN条件的使用规则,希望可以帮助开发者精准控制查询逻辑... 目录一、ON与WHERE的本质区别二、场景化条件使用规则三、最佳实践建议1.优先使用ON条件2.WHERE用

Linux链表操作方式

《Linux链表操作方式》:本文主要介绍Linux链表操作方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、链表基础概念与内核链表优势二、内核链表结构与宏解析三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势六、典型应用场景七、调试技巧与

Java Multimap实现类与操作的具体示例

《JavaMultimap实现类与操作的具体示例》Multimap出现在Google的Guava库中,它为Java提供了更加灵活的集合操作,:本文主要介绍JavaMultimap实现类与操作的... 目录一、Multimap 概述Multimap 主要特点:二、Multimap 实现类1. ListMult

Python中文件读取操作漏洞深度解析与防护指南

《Python中文件读取操作漏洞深度解析与防护指南》在Web应用开发中,文件操作是最基础也最危险的功能之一,这篇文章将全面剖析Python环境中常见的文件读取漏洞类型,成因及防护方案,感兴趣的小伙伴可... 目录引言一、静态资源处理中的路径穿越漏洞1.1 典型漏洞场景1.2 os.path.join()的陷

Python使用Code2flow将代码转化为流程图的操作教程

《Python使用Code2flow将代码转化为流程图的操作教程》Code2flow是一款开源工具,能够将代码自动转换为流程图,该工具对于代码审查、调试和理解大型代码库非常有用,在这篇博客中,我们将深... 目录引言1nVflRA、为什么选择 Code2flow?2、安装 Code2flow3、基本功能演示

Python中OpenCV与Matplotlib的图像操作入门指南

《Python中OpenCV与Matplotlib的图像操作入门指南》:本文主要介绍Python中OpenCV与Matplotlib的图像操作指南,本文通过实例代码给大家介绍的非常详细,对大家的学... 目录一、环境准备二、图像的基本操作1. 图像读取、显示与保存 使用OpenCV操作2. 像素级操作3.

python多线程并发测试过程

《python多线程并发测试过程》:本文主要介绍python多线程并发测试过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、并发与并行?二、同步与异步的概念?三、线程与进程的区别?需求1:多线程执行不同任务需求2:多线程执行相同任务总结一、并发与并行?1、

python操作redis基础

《python操作redis基础》Redis(RemoteDictionaryServer)是一个开源的、基于内存的键值对(Key-Value)存储系统,它通常用作数据库、缓存和消息代理,这篇文章... 目录1. Redis 简介2. 前提条件3. 安装 python Redis 客户端库4. 连接到 Re

Java Stream.reduce()方法操作实际案例讲解

《JavaStream.reduce()方法操作实际案例讲解》reduce是JavaStreamAPI中的一个核心操作,用于将流中的元素组合起来产生单个结果,:本文主要介绍JavaStream.... 目录一、reduce的基本概念1. 什么是reduce操作2. reduce方法的三种形式二、reduce

MySQL表空间结构详解表空间到段页操作

《MySQL表空间结构详解表空间到段页操作》在MySQL架构和存储引擎专题中介绍了使用不同存储引擎创建表时生成的表空间数据文件,在本章节主要介绍使用InnoDB存储引擎创建表时生成的表空间数据文件,对... 目录️‍一、什么是表空间结构1.1 表空间与表空间文件的关系是什么?️‍二、用户数据在表空间中是怎么