iOS - 使用 SQLite 数据库实现数据持久化
前言
SQLite 是一款主流的嵌入式关系型数据库,它的主要特点是轻量级和跨平台,是当前很多嵌入式操作系统中数据库的首选。
数据库也是客户端开发中常用的一种数据持久化手段,本文主要介绍在客户端开发中常用的数据库 SQLite,结合一个简单的理解讲解它引入、创建到后面 CRUD 的操作。
文章目录
- 前言
- 1. sqlite3 引入
- 2. sqlite3 的使用
- 2.1 VGUserDAO 的封装
- 2.2 建表操作
- 2.3 查询操作
- 2.4 插入操作
- 2.5 修改操作
- 2.6 删除操作
- 参考资料
1. sqlite3 引入
要想在 iOS 开发中使用 SQLite 数据库,先要导入 libsqlite3.tbd。具体路径是 TARGETS -> Build Phases -> Link Binary With Libraries
。操作如下图所示:
2. sqlite3 的使用
这里以一个简单的例子来介绍 sqlite3 的使用,我们有个用户表,里面有用户id,用户名称和用户年龄等三个字段,我们使用 sqlite3 对它进行增删改查。
下面是用户类的定义:
@interface VGUser : NSObject// 用户ID
@property (nonatomic, copy) NSString *userId;
// 用户名
@property (nonatomic, copy) NSString *userName;
// 用户年龄
@property (nonatomic, assign) NSInteger userAge;- (instancetype)initWithUserId:(NSString *)userIduserName:(NSString *)userNameuserAge:(NSInteger)userAge;@end
2.1 VGUserDAO 的封装
为了满足我们的需求,我们封装一个 VGUserDAO
类来实现我们要的操作,主要实现下面方法:
@interface VGUserDAO : NSObject/// 获取 VGUserDAO 单例
+ (instancetype)sheredInstance;/// 查找特定ID的用户
- (VGUser *)findById:(NSString *)userId;/// 查询所有用户
- (NSArray *)findAll;/// 在数据表中插入一行数据
- (void)create:(VGUser *)user;/// 删除特定ID的用户
- (void)remove:(NSString *)userId;/// 修改用户信息
- (void)modify:(VGUser *)user;@end
VGUserDAO.m 文件的部分代码
#import "VGUser.h"
#import <sqlite3.h>#define DBFILE_NAME @"UserList.sqlite3"@interface VGUserDAO () {sqlite3 *_db; // 数据库对象
}// 数据库的存储路径
@property (nonatomic, strong) NSString *plistFilePath;@end@implementation VGUserDAO+ (instancetype)sheredInstance {static VGUserDAO *sharedInstance = nil;static dispatch_once_t onceToken;dispatch_once(&onceToken, ^ {sharedInstance = [[VGUserDAO alloc] init];// 设置数据库的存储路径sharedInstance.plistFilePath = [sharedInstance applicationDocumentsDirectory];// 执行检表操作[sharedInstance createEditableDatabaseIfNeed];});return sharedInstance;
}// 获取数据库的存储路径
- (NSString *)applicationDocumentsDirectory {NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, TRUE) lastObject];NSString *path = [docDir stringByAppendingPathComponent:DBFILE_NAME];return path;
}//......@end
2.2 建表操作
建表操作主要包含以下几个步骤:
- 使用
sqlite3_open
函数打开数据库 - 使用
sqlite3_exec
函数执行建表的 SQL 语句,创建用户表 - 使用
sqlite3_close
函数关闭数据库,释放资源
具体的代码实现如下:
- (void)createEditableDatabaseIfNeed {const char *cpath = self.plistFilePath.UTF8String;// sqlite3_open// 1. filename 是数据库文件的完整路径// 2. ppDb 是sqlite3类型指针变量的地址if (sqlite3_open(cpath, &_db) != SQLITE_OK) {NSLog(@"数据库打开失败");} else {NSString *sql = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS User (user_id TEXT PRIMARY KEY, user_name TEXT, user_age INTEGER);"];const char *cSql = sql.UTF8String;// sqlite3_exec// 1. sqlite3类型指针变量,表示数据库// 2. sql 是要执行的sql语句// 3. 要回调的函数指针// 4. 要回调的函数的第一个参数// 5. 执行出错信息的字符串if (sqlite3_exec(_db, cSql, NULL, NULL, NULL) != SQLITE_OK) {NSLog(@"建表失败");}}// 关闭数据库sqlite3_close(_db);
}
建表的时候需要指定数据类型,SQLite 支持的常见数据类型如下所示:
integer
,有符号的整数类型real
,浮点数text
,字符串类型,采用 UTF-8 和 UTF-16 编码blob
,二进制大对象类型,能够存放任何二进制数据
2.3 查询操作
使用 sqlite3 执行查询操作,主要包括如下步骤:
- 使用
sqlite3_open
函数打开数据库 - 使用
sqlite3_prepare_v2
函数预处理 SQL 语句 - 使用
sqlite3_bind_text
等函数绑定参数 - 使用
sqlite3_step
函数执行 SQL 语句 - 使用
sqlite3_column_text
等函数提取结果集中的字段 - 使用
sqlite3_finalize
和sqlite3_close
函数释放资源
下面是对根据 ID 查询特定用户的方法的实现:
- (VGUser *)findById:(NSString *)userId {const char *cpath = self.plistFilePath.UTF8String;if (sqlite3_open(cpath, &_db) != SQLITE_OK) {NSLog(@"数据库打开失败");} else {NSString *sql = @"select user_id, user_name, user_age from user where user_id = ?";const char *cSql = sql.UTF8String;// 语句对象sqlite3_stmt *statement;// sqlite3_prepare_v2 SQL预处理函数// 1. db 是sqlite3类型指针变量,表示数据库// 2. zSql 是要执行的SQL语句// 3. nByte 是全部SQL字符串的最大长度// 4. ppStmt 是sqlite3_stmt类型指针的地址,表示语句对象// 5. pzTail 是zSql没有执行部分if (sqlite3_prepare_v2(_db, cSql, -1, &statement, NULL) == SQLITE_OK) {const char *cUserId = userId.UTF8String;// sqlite3_bind_text 绑定SQL语句TEXT类型的参数// 1. sqlite3_stmt类型指针// 2. 参数的序号,从 1 开始// 3. 参数的值// 4. 字符串长度// 5. 函数指针sqlite3_bind_text(statement, 1, cUserId, -1, NULL);// sqlite3_step 执行语句if (sqlite3_step(statement) == SQLITE_ROW) {// sqlite3_column_text 读取字符串类型数据// 1. 语句对象// 2. SELECT字段的索引,从 0 开始char *bufUserId = (char *)sqlite3_column_text(statement, 0);char *bufUserName = (char *)sqlite3_column_text(statement, 1);// sqlite3_column_int 读取int类型数据int bufUserAge = sqlite3_column_int(statement, 2);NSString *strUserId = [[NSString alloc] initWithUTF8String:bufUserId];NSString *strUserName = [[NSString alloc] initWithUTF8String:bufUserName];VGUser *user = [[VGUser alloc] initWithUserId:strUserIduserName:strUserNameuserAge:bufUserAge];// 释放语句对象sqlite3_finalize(statement);sqlite3_close(_db);return user;}}sqlite3_finalize(statement);}sqlite3_close(_db);return nil;
}
下面是对查找所有用户的方法的实现:
- (NSArray *)findAll {const char *cpath = self.plistFilePath.UTF8String;NSMutableArray *userList = [NSMutableArray array];if (sqlite3_open(cpath, &_db) != SQLITE_OK) {NSLog(@"数据库打开失败");} else {NSString *sql = @"select user_id, user_name, user_age from user";const char *cSql = sql.UTF8String;sqlite3_stmt *statement;if (sqlite3_prepare_v2(_db, cSql, -1, &statement, NULL) == SQLITE_OK) {// 常量 SQLITE_ROW 表示结果集中还有数据while (sqlite3_step(statement) == SQLITE_ROW) {char *bufUserId = (char *)sqlite3_column_text(statement, 0);char *bufUserName = (char *)sqlite3_column_text(statement, 1);int bufUserAge = sqlite3_column_int(statement, 2);NSString *strUserId = [[NSString alloc] initWithUTF8String:bufUserId];NSString *strUserName = [[NSString alloc] initWithUTF8String:bufUserName];VGUser *user = [[VGUser alloc] initWithUserId:strUserIduserName:strUserNameuserAge:bufUserAge];[userList addObject:user];}}sqlite3_finalize(statement);}sqlite3_close(_db);return [userList copy];
}
在进行字段读取的时候,根据字段类型的不同,有下面几种常用函数:
sqlite3_column_int()
sqlite3_column_int64()
sqlite3_column_double()
sqlite3_column_text()
sqlite3_column_text16()
sqlite3_column_blob()
我们可以根据字段的类型,选择合适的函数。参数绑定函数 sqlite3_bind_text
也是同理。
2.4 插入操作
使用 sqlite3 执行插入操作,主要包含如下步骤:
- 使用
sqlite3_open
函数打开数据库 - 使用
sqlite3_prepare_v2
函数预处理 SQL 语句 - 使用
sqlite3_bind_text
等函数绑定参数 - 使用
sqlite3_step
函数执行 SQL 语句 - 使用
sqlite3_finalize
和sqlite3_close
函数释放资源
- (void)create:(VGUser *)user {const char *cpath = self.plistFilePath.UTF8String;if (sqlite3_open(cpath, &_db) != SQLITE_OK) {NSLog(@"数据库打开失败");} else {NSString *sql = @"insert or replace into user (user_id, user_name, user_age) values (?, ?, ?)";const char *cSql = sql.UTF8String;sqlite3_stmt *statement;if (sqlite3_prepare_v2(_db, cSql, -1, &statement, NULL) == SQLITE_OK) {const char *cUserId = user.userId.UTF8String;const char *cUserName = user.userName.UTF8String;const int cUserAge = (int)user.userAge;sqlite3_bind_text(statement, 1, cUserId, -1, NULL);sqlite3_bind_text(statement, 2, cUserName, -1, NULL);sqlite3_bind_int(statement, 3, cUserAge);if (sqlite3_step(statement) != SQLITE_DONE) {NSLog(@"数据插入失败");}}sqlite3_finalize(statement);}sqlite3_close(_db);
}
2.5 修改操作
对与修改操作而言,已经没有新东西可言了,主要差别还是在 SQL 语句,插入、修改和删除用的分别是 insert
、 update
和 delete
。
- (void)modify:(VGUser *)user {const char *cpath = self.plistFilePath.UTF8String;if (sqlite3_open(cpath, &_db) != SQLITE_OK) {NSLog(@"数据库打开失败");} else {NSString *sql = @"update user set user_name = ?, user_age = ? where user_id = ?";const char *cSql = sql.UTF8String;sqlite3_stmt *statement;if (sqlite3_prepare_v2(_db, cSql, -1, &statement, NULL) == SQLITE_OK) {const char *cUserId = user.userId.UTF8String;const char *cUserName = user.userName.UTF8String;const int cUserAge = (int)user.userAge;sqlite3_bind_text(statement, 1, cUserName, -1, NULL);sqlite3_bind_int(statement, 2, cUserAge);sqlite3_bind_text(statement, 3, cUserId, -1, NULL);if (sqlite3_step(statement) != SQLITE_DONE) {NSLog(@"数据修改失败");}}sqlite3_finalize(statement);}sqlite3_close(_db);
}
2.6 删除操作
- (void)remove:(NSString *)userId {const char *cpath = self.plistFilePath.UTF8String;if (sqlite3_open(cpath, &_db) != SQLITE_OK) {NSLog(@"数据库打开失败");} else {NSString *sql = @"delete from user where user_id = ?";const char *cSql = sql.UTF8String;sqlite3_stmt *statement;if (sqlite3_prepare_v2(_db, cSql, -1, &statement, NULL) == SQLITE_OK) {const char *cUserId = userId.UTF8String;sqlite3_bind_text(statement, 1, cUserId, -1, NULL);if (sqlite3_step(statement) != SQLITE_DONE) {NSLog(@"数据删除失败");}}sqlite3_finalize(statement);}sqlite3_close(_db);
}
参考资料
- 《iOS开发指南:从Hello World到App Store上架(第5版)》
iOS - 使用 SQLite 数据库实现数据持久化相关推荐
- 使用嵌入式关系型SQLite数据库存储数据
除了可以使用文件或SharedPreferences存储数据,还可以选择使用SQLite数据库存储数据. 在Android平台上,集成了一个嵌入式关系型数据库-SQLite,SQLite3支持 NUL ...
- 【转】Android使用嵌入式关系型SQLite数据库存储数据【学习记录】
为什么80%的码农都做不了架构师?>>> 除了可以使用文件或SharedPreferences存储数据,还可以选择使用SQLite数据库存储数据. 在Android平台上,集成 ...
- iOS - Swift SQLite 数据库存储
前言 采用 SQLite 数据库来存储数据.SQLite 作为一中小型数据库,应用 iOS 中,跟前三种保存方式相比,相对比较复杂一些. 注意:写入数据库,字符串可以采用 char 方式,而从数据库中 ...
- iOS - OC SQLite 数据库存储
前言 采用 SQLite 数据库来存储数据.SQLite 作为一中小型数据库,应用 iOS 中,跟前三种保存方式相比,相对比较复杂一些. 注意:写入数据库,字符串可以采用 char 方式,而从数据库中 ...
- iOS编程------SQLite / 数据库
/* # Sqlite3## 创建数据库方法 ## 一.终端命令进入到 /Users/wushumin/Documents/Sqlite 文件夹下. > cd Documents/Sqlite ...
- 使用SQLite数据库存储数据(1)-操作SQLite数据库
在使用SQLite API函数如有疑问,可以参考官方函数文档: http://www.sqlite.org/c3ref/funclist.html 操作SQLite数据库 SQLite数据库是文件数据 ...
- mfc从mysql中读取数据类型_在MFC中使用SQlite数据库读取数据
本人在数据库里面用回调函数来处理读取函数的返回值,回调函数必须使用static类型才可以,这样处理起返回的数据变得非常的麻烦,很难处理结果集. 后来从网上找了一个预编译的例子,放在网上和网友分享. 例 ...
- do与mysql数据类型对照_dophon-db: dophon框架的数据库模块,支持mysql,sqlite数据库,带有orm持久化功能与链式操作实例,贴近逻辑习惯,支持mysql多数据源配置...
dophon-db 项目介绍 dophon框架的数据库模块,也可单独作为一个与数据库模块交互的部件 支持mysql数据库连接 支持orm形式的数据操作 如有疑问请发送邮件联系作者:ealohu@163 ...
- 使用SQLite数据库存储数据(2)-向表中插入记录
向表中插入记录 向数据表Notebook中添加一条新的记事日志,成功插入记录后,会显示一个提醒视图. - (IBAction)addNote:(id)sender { char *errMsg; co ...
最新文章
- linux 内核函数 copy_from_user和copy_to_user 介绍
- python 重复输出字符串
- @有两个含义:1,在参数里,以表明该变量为伪参数 ,在本例中下文里将用@name变量代入当前代码中2,在字串中,@的意思就是后面的字串以它原本的含义显示,如果不...
- 大对象简介+大对象的4种类型+lob类型的优点+lob的组成
- mysql优化学习笔记
- Java继承注意事项难点理解
- 第2关:子节点创建、列出、删除
- 怎样从Mysql官网下载linux版本的mysql安装包
- Tomas Mikolov's Recurrent Neural Networks Language Modeling Toolkit
- 51单片机LCD1602显示
- java控制html弹出框,Selenium+java - 弹出框处理
- 烂土豆搭配令牌窃取提权dll劫持搭配令牌窃取提权不带引号服务路径问题提权不安全的服务权限配置提权
- 新买笔记本屏幕缝隙有灰尘_如何清除笔记本电脑上的灰尘
- Linux环境下Python操作word
- 用amCharts插件实现树状图
- 鸿蒙中国壁纸高清全面屏,华为P50pro最新确认:麒麟1020+立体全面屏+鸿蒙系统,这才是华为...
- 打造我们心中永恒的m500
- Android自定义view-电子签名画板
- 《数据库系统概论》复习笔记
- web ctf解题记录 bugku的ctf_论剑场