iOS数据持久化-SQLite数据库使用详解

简介: <h1><strong>使用SQLite数据库</strong></h1><h2><strong>创建数据库</strong></h2><p>创建数据库过程需要3个步骤:</p><p>1、使用sqlite3_open函数打开数据库;</p><p>2、使用sqlite3_exec函数执行Create Table语句,创建数据库表;</p><p>3、使用sqlite3_close函数释放

使用SQLite数据库

创建数据库

创建数据库过程需要3个步骤:

1、使用sqlite3_open函数打开数据库;

2、使用sqlite3_exec函数执行Create Table语句,创建数据库表;

3、使用sqlite3_close函数释放资源。

这个过程中使用了3个SQLite3函数,它们都是纯C语言函数,通过Objective-C去调用C函数当然不是什么问题,但是也要注意Objective-C数据类型与C数据类型兼容性问题。

下面我们使用SQLite技术实现备忘录案例,与属性列表文件实现一样,我们只需要修改持久层工程(PersistenceLayer)中NoteDAO类就可以了。首先我们需要添加SQLite3库到工程环境中,有3个工程需要添加到哪个呢?应该添加到可以运行的工程即表示层工程PresentationLayer。选择工程PresentationLayer中TARGETS→PresentationLayer→Link Binary With Libraries,点击左下角的“+”,弹出对话框选择libsqlite3.dylib或libsqlite3.0.dylib,在弹出的对话框中点击Add添加。

1

NoteDAO.h文件的修改:

#import ”Note.h”

#import ”sqlite3.h”

 

#define DBFILE_NAME @”NotesList.sqlite3″

 

@interface NoteDAO : NSObject

{

sqlite3 *db;

}

 

+ (NoteDAO*)sharedManager;

 

- (NSString *)applicationDocumentsDirectoryFile;

- (void)createEditableCopyOfDatabaseIfNeeded;

 

//插入Note方法

-(int) create:(Note*)model;

 

//删除Note方法

-(int) remove:(Note*)model;

 

//修改Note方法

-(int) modify:(Note*)model;

 

//查询所有数据方法

-(NSMutableArray*) findAll;

 

//按照主键查询数据方法

-(Note*) findById:(Note*)model;

 

@end


我们需要使用语句#import ”sqlite3.h”引入sqlite3头文件,而且需要定义sqlite3*成员变量db。NoteDAO.m中的createEditableCopyOfDatabaseIfNeeded方法:

- (void)createEditableCopyOfDatabaseIfNeeded {

 

NSString *writableDBPath = [self applicationDocumentsDirectoryFile];

if (sqlite3_open([writableDBPath UTF8String], &db) != SQLITE_OK) { ①

sqlite3_close(db);  ②

NSAssert(NO,@”数据库打开失败。”);

} else {

char *err;

NSString *createSQL = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS Note

(cdate TEXT PRIMARY KEY, content TEXT);"]; ③

if (sqlite3_exec(db,[createSQL UTF8String],NULL,NULL,&err) != SQLITE_OK) { ④

sqlite3_close(db); ⑤

NSAssert1(NO, @”建表失败, %s”, err);  ⑥

}

sqlite3_close(db);  ⑦

}

}


createEditableCopyOfDatabaseIfNeeded方法用于创建数据库,第1步打开数据库,代码①行,语句是sqlite3_open([writableDBPath UTF8String], &db),sqlite3_open函数的第1个参数是数据库文件完整的路径,但是需要注意的是在SQLite3函数中接受的是char*的UTF-8类型数据,需要将NSString*转换为UTF-8,使用NSString*的UTF8String方法可以转换,sqlite3_open函数第2个参数sqlite3指针变量db的地址。该函数的返回值是int类型,在SQLite3中定义了很多常量,返回值等于常量SQLITE_OK则说明操作成功。

第2步执行建表语句,代码第④行,语句sqlite3_exec(db,[createSQL UTF8String],NULL,NULL,&err)执行建表的SQL。第1个参数是sqlite3指针变量db的地址,第2个参数是要执行的sql语句,第3个参数是要回调函数,第4个参数是要回调函数的参数,第5个参数是执行出错的字符串。建表SQL语句是,如果表Note存在这不用创建。

CREATE TABLE IF NOT EXISTS Note (cdate TEXT PRIMARY KEY, content TEXT)

第3步使用sqlite3_close函数释放资源,代码②、⑤、⑦行所示,在数据库打开失败、Create Table执行失败和成功执行完成时候调用。原则上无论正常结束还是异常结束必须使用sqlite3_close函数释放资源。

查询数据

数据查询一般会带有查询条件,这个使用SQL语句where子句很容易实现,但是在程序中需要动态绑定参数给where子句。执行查询数据步骤如下:

1、使用sqlite3_open函数打开数据库;

2、使用sqlite3_prepare_v2函数预处理SQL语句;

3、使用sqlite3_bind_text函数绑定参数;

4、使用sqlite3_step函数执行SQL语句,遍历结果集;

5、使用sqlite3_column_text等函数提取字段数据;

6、使用sqlite3_finalize和sqlite3_close函数释放资源。

NoteDAO.m中的按照主键查询数据方法:

-(Note*) findById:(Note*)model

{

NSString *path = [self applicationDocumentsDirectoryFile];

if (sqlite3_open([path UTF8String], &db) != SQLITE_OK) { ①

sqlite3_close(db);  ②

NSAssert(NO,@”数据库打开失败。”);

} else {

 

NSString *qsql = @”SELECT cdate,content FROM Note where cdate =?”;

 

sqlite3_stmt *statement;

//预处理过程

if (sqlite3_prepare_v2(db, [qsql UTF8String], -1, &statement, NULL) == SQLITE_OK) { ③

//准备参数

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; ④

[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];

NSString *nsdate = [dateFormatter stringFromDate:model.date];

//绑定参数开始

sqlite3_bind_text(statement, 1, [nsdate UTF8String], -1, NULL); ⑤

//执行

if (sqlite3_step(statement) == SQLITE_ROW) { ⑥

char *cdate = (char *) sqlite3_column_text(statement, 0); ⑦

NSString *nscdate = [[NSString alloc] initWithUTF8String: cdate];

 

char *content = (char *) sqlite3_column_text(statement, 1);

NSString * nscontent = [[NSString alloc] initWithUTF8String: content];

Note* note = [[Note alloc] init];

note.date = [dateFormatter dateFromString:nscdate];

note.content = nscontent;

 

sqlite3_finalize(statement);

sqlite3_close(db);

return note;

}

}

 

sqlite3_finalize(statement); ⑧

sqlite3_close(db);  ⑨

 

}

return nil;

}


该方法执行了6个步骤,其中第1个步骤,代码第①行所示,它与创建数库的第1个步骤是一样的,不用再介绍了。

第2个步骤,代码第③行所示,语句sqlite3_prepare_v2(db, [qsql UTF8String], -1, &statement, NULL)是预处理SQL语句,预处理目的是将SQL编译成二进制代码,提高SQL语句执行的速度。sqlite3_prepare_v2函数的第3个参数-1代表全部sql字符串长度,第4个参数&statement是sqlite3_stmt指针的地址,它是语句对象,通过语句对象可以执行SQL语句,第5个参数是sql语句没有被执行的部分语句。

第3个步骤,代码第⑤行所示,语句sqlite3_bind_text(statement, 1, [nsdate UTF8String], -1, NULL)是绑定SQL语句参数。在SQL语句中带有问号,这个问号就是要绑定的参数,问号是占位符。

NSString *qsql = @”SELECT cdate,content FROM Note where cdate =?”;

sqlite3_bind_text函数是绑定参数,第1个参数是statement指针,第2个参数为序号(从1开始),第3个参数为字符串值,第4个参数为字符串长度,第5个参数为一个函数指针。

第4个步骤sqlite3_step(statement)执行SQL语句,代码第⑥行所示,sqlite3_step返回int类型,等于SQLITE_ROW说明还要其它的行没有遍历。

第5个步骤提取字段数据,代码第⑦行所示,使用sqlite3_column_text(statement, 0)函数可以读取字符串类型字段,第2参数是指定select字段的索引(从0开始)。同样char*转换成为NSString*类型,需要initWithUTF8String:构造方法。读取字段函数采用与字段类型有关系,SQLite3的类似的常用函数还有:

sqlite3_column_blob()

sqlite3_column_double()

sqlite3_column_int()

sqlite3_column_int64()

sqlite3_column_text()

sqlite3_column_text16()

关于其它的API可以参考http://www.sqlite.org/cintro.html。

第6个步骤是释放资源,创建数据库过程不同,除了使用sqlite3_close函数关闭数据库,代码第⑧行所示,还要使用sqlite3_finalize函数释放语句对象statement代码第⑨行所示。

NoteDAO.m中的查询所有数据方法:

-(NSMutableArray*) findAll

{

NSString *path = [self applicationDocumentsDirectoryFile];

NSMutableArray *listData = [[NSMutableArray alloc] init];

if (sqlite3_open([path UTF8String], &db) != SQLITE_OK) {

sqlite3_close(db);

NSAssert(NO,@”数据库打开失败。”);

} else {

 

NSString *qsql = @”SELECT cdate,content FROM Note”;

 

sqlite3_stmt *statement;

//预处理过程

if (sqlite3_prepare_v2(db, [qsql UTF8String], -1, &statement, NULL) == SQLITE_OK) {

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];

[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];

//执行

while (sqlite3_step(statement) == SQLITE_ROW) {

char *cdate = (char *) sqlite3_column_text(statement, 0);

NSString *nscdate = [[NSString alloc] initWithUTF8String: cdate];

 

char *content = (char *) sqlite3_column_text(statement, 1);

NSString * nscontent = [[NSString alloc] initWithUTF8String: content];

Note* note = [[Note alloc] init];

note.date = [dateFormatter dateFromString:nscdate];

note.content = nscontent;

[listData addObject:note];

}

}

 

sqlite3_finalize(statement);

sqlite3_close(db);

 

}

return listData;

}


查询所有数据方法与按照主键查询数据方法类似,区别在于本方法没有查询条件不需要绑定参数。遍历的时候使用while循环语句,不是if语句。

while (sqlite3_step(statement) == SQLITE_ROW) {

… …

}

修改数据 

修改数据包括:insert、update和delete语句。这3个SQL语句都可以带有参数,关于参数的绑定与查询where子句绑定的方式是一样的。执行修改数据步骤如下:

1、使用sqlite3_open函数打开数据库;

2、使用sqlite3_prepare_v2函数预处理SQL语句;

3、使用sqlite3_bind_text函数绑定参数;

4、使用sqlite3_step函数执行SQL语句;

5、使用sqlite3_finalize和sqlite3_close函数释放资源。

修改数据的步骤与查询数据的步骤相比少了一个提取字段数据步骤。下面我们看看代码部分。其它的步骤是一样的。

NoteDAO.m中的插入Note方法:

-(int) create:(Note*)model

{

NSString *path = [self applicationDocumentsDirectoryFile];

if (sqlite3_open([path UTF8String], &db) != SQLITE_OK) { ①

sqlite3_close(db);  ②

NSAssert(NO,@”数据库打开失败。”);

} else {

 

NSString *sqlStr = @”INSERT OR REPLACE INTO note (cdate, content) VALUES (?,?)”;

 

sqlite3_stmt *statement;

//预处理过程

if (sqlite3_prepare_v2(db, [sqlStr UTF8String], -1, &statement, NULL) == SQLITE_OK) { ③

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];

[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];

NSString *nsdate = [dateFormatter stringFromDate:model.date];

//绑定参数开始

sqlite3_bind_text(statement, 1, [nsdate UTF8String], -1, NULL);  ④

sqlite3_bind_text(statement, 2, [model.content UTF8String], -1, NULL);

 

//执行插入

if (sqlite3_step(statement) != SQLITE_DONE) { ⑤

NSAssert(NO, @”插入数据失败。”);

}

}

 

sqlite3_finalize(statement);  ⑥

sqlite3_close(db);  ⑦

}

return 0;

}


第⑤行代码sqlite3_step(statement)语句执行插入语句,常量SQLITE_DONE执行完成。

NoteDAO.m中的删除Note方法:

-(int) remove:(Note*)model

{

NSString *path = [self applicationDocumentsDirectoryFile];

if (sqlite3_open([path UTF8String], &db) != SQLITE_OK) {

sqlite3_close(db);

NSAssert(NO,@”数据库打开失败。”);

} else {

 

NSString *sqlStr = @”DELETE  from note where cdate =?”;

 

sqlite3_stmt *statement;

//预处理过程

if (sqlite3_prepare_v2(db, [sqlStr UTF8String], -1, &statement, NULL) == SQLITE_OK) {

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];

[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];

NSString *nsdate = [dateFormatter stringFromDate:model.date];

//绑定参数开始

sqlite3_bind_text(statement, 1, [nsdate UTF8String], -1, NULL);

//执行插入

if (sqlite3_step(statement) != SQLITE_DONE) {

NSAssert(NO, @”删除数据失败。”);

}

}

 

sqlite3_finalize(statement);

sqlite3_close(db);

}

return 0;

}

NoteDAO.m中的修改Note方法:

-(int) modify:(Note*)model

{

NSString *path = [self applicationDocumentsDirectoryFile];

if (sqlite3_open([path UTF8String], &db) != SQLITE_OK) {

sqlite3_close(db);

NSAssert(NO,@”数据库打开失败。”);

} else {

 

NSString *sqlStr = @”UPDATE note set content=? where cdate =?”;

 

sqlite3_stmt *statement;

//预处理过程

if (sqlite3_prepare_v2(db, [sqlStr UTF8String], -1, &statement, NULL) == SQLITE_OK) {

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];

[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];

NSString *nsdate = [dateFormatter stringFromDate:model.date];

//绑定参数开始

sqlite3_bind_text(statement, 1, [model.content UTF8String], -1, NULL);

sqlite3_bind_text(statement, 2, [nsdate UTF8String], -1, NULL);

//执行插入

if (sqlite3_step(statement) != SQLITE_DONE) {

NSAssert(NO, @”修改数据失败。”);

}

}

 

sqlite3_finalize(statement);

sqlite3_close(db);

}

return 0;

}


目录
打赏
0
0
0
0
26
分享
相关文章
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
369 4
云栖重磅|从数据到智能:Data+AI驱动的云原生数据库
在9月20日2024云栖大会上,阿里云智能集团副总裁,数据库产品事业部负责人,ACM、CCF、IEEE会士(Fellow)李飞飞发表《从数据到智能:Data+AI驱动的云原生数据库》主题演讲。他表示,数据是生成式AI的核心资产,大模型时代的数据管理系统需具备多模处理和实时分析能力。阿里云瑶池将数据+AI全面融合,构建一站式多模数据管理平台,以数据驱动决策与创新,为用户提供像“搭积木”一样易用、好用、高可用的使用体验。
云栖重磅|从数据到智能:Data+AI驱动的云原生数据库
有哪些方法可以验证用户输入数据的格式是否符合数据库的要求?
有哪些方法可以验证用户输入数据的格式是否符合数据库的要求?
157 75
Hutool创建数据源工厂动态查询不同数据库不同数据表的数据
Hutool创建数据源工厂动态查询不同数据库不同数据表的数据
20 2
flink 向doris 数据库写入数据时出现背压如何排查?
本文介绍了如何确定和解决Flink任务向Doris数据库写入数据时遇到的背压问题。首先通过Flink Web UI和性能指标监控识别背压,然后从Doris数据库性能、网络连接稳定性、Flink任务数据处理逻辑及资源配置等方面排查原因,并通过分析相关日志进一步定位问题。
310 61
|
2月前
|
从建模到运维:联犀如何完美融入时序数据库 TDengine 实现物联网数据流畅管理
本篇文章是“2024,我想和 TDengine 谈谈”征文活动的三等奖作品。文章从一个具体的业务场景出发,分析了企业在面对海量时序数据时的挑战,并提出了利用 TDengine 高效处理和存储数据的方法,帮助企业解决在数据采集、存储、分析等方面的痛点。通过这篇文章,作者不仅展示了自己对数据处理技术的理解,还进一步阐释了时序数据库在行业中的潜力与应用价值,为读者提供了很多实际的操作思路和技术选型的参考。
57 1
招行面试:100万级别数据的Excel,如何秒级导入到数据库?
本文由40岁老架构师尼恩撰写,分享了应对招商银行Java后端面试绝命12题的经验。文章详细介绍了如何通过系统化准备,在面试中展示强大的技术实力。针对百万级数据的Excel导入难题,尼恩推荐使用阿里巴巴开源的EasyExcel框架,并结合高性能分片读取、Disruptor队列缓冲和高并发批量写入的架构方案,实现高效的数据处理。此外,文章还提供了完整的代码示例和配置说明,帮助读者快速掌握相关技能。建议读者参考《尼恩Java面试宝典PDF》进行系统化刷题,提升面试竞争力。关注公众号【技术自由圈】可获取更多技术资源和指导。
获取数据库中字段的数据作为下拉框选项
获取数据库中字段的数据作为下拉框选项
69 5
Python处理数据库:MySQL与SQLite详解 | python小知识
本文详细介绍了如何使用Python操作MySQL和SQLite数据库,包括安装必要的库、连接数据库、执行增删改查等基本操作,适合初学者快速上手。
399 15
国产数据实战之docker部署MyWebSQL数据库管理工具
【10月更文挑战第23天】国产数据实战之docker部署MyWebSQL数据库管理工具
294 4
国产数据实战之docker部署MyWebSQL数据库管理工具

热门文章

最新文章

  • 1
    iOS各个证书生成细节
    18
  • 2
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    69
  • 3
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    34
  • 4
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    50
  • 5
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    42
  • 6
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
    36
  • 7
    uniapp开发ios打包Error code = -5000 Error message: Error: certificate file(p12) import failed!报错问题如何解决
    147
  • 8
    【05】2025年1月首发完整版-篇幅较长-苹果app如何上架到app store完整流程·不借助第三方上架工具的情况下无需花钱但需仔细学习-优雅草央千澈详解关于APP签名以及分发-们最关心的一篇来了-IOS上架app
    284
  • 9
    app开发之安卓Android+苹果ios打包所有权限对应解释列表【长期更新】-以及默认打包自动添加权限列表和简化后的基本打包权限列表以uniapp为例-优雅草央千澈
    99
  • 10
    深入探索iOS开发中的SwiftUI框架
    149
  • AI助理

    你好,我是AI助理

    可以解答问题、推荐解决方案等