设为首页 收藏本站
查看: 1394|回复: 0

[经验分享] iOS数据持久化-SQLite数据库使用详解

[复制链接]

尚未签到

发表于 2016-12-1 06:31:54 | 显示全部楼层 |阅读模式
使用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添加。

  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;
}
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-307781-1-1.html 上篇帖子: Android提高第八篇之SQLite分页读取 下篇帖子: 使用SQLite遇到单引号
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表