这周比较忙, 前几天都加班到 11 点左右, 基本都是到家都是 12 点左右 (稍稍的抱怨一下, 免费加班, 何为免费, 就是任何补偿都没有, 例如调休, 加班薪, 餐补等各项福利, 是一点都没有呀) 因为 App 要上线了! App 上线, 也可以抽出部分时间整理自己的东西啦, 准备花一周时间讲述 iOS 数据存储方式. 本篇主要是讲 SQLite 的使用和封装, 读完大约 10-15 分钟.
一, SQLite 概念
SQLite 是轻量型关系型数据库 (下面将拓展关系型数据库的概念); 占用资源非常少; 是无类型的数据库(意思是可以保存所有类型的数据)----B 树为 SQLite 提供了 O(logN) 的查询, 插入以及删除操作, 同时提供了 O(1)的对记录的遍历操作.
拓展
1. 关系型数据库与非关系型数据库
关系型数据库是建立在关系型模型的数据库, 关系型数据库是通过外键来建立表与表之间的关系, 而非关系型数据库是以对象的形式存在数据库中(对象之间的关系是通过对象自身的属性来确定的)
举一个例子:
比如 有一个学生的数据:
姓名: 张四, 性别: 男, 学号: 12345678, 班级: 大学一班
一个班级的数据:
班级: 大学一班, 班主任: 李四
针对这个例子: 关系型数据库, 需要创建学生表和班级表来存储这两条数据, 而且学生表中的班级存储应该是班级表的主键. 对于非关系型数据库中, 我们需要创建两个对象, 一个是学生对象, 一个是班级对象, 用 java 表示如下:
- class Student {
- String id;
- String name;
- String sex;
- String number;
- String classid;
- }
- class Grade {
- String id;
- String name;
- String teacher;
- }
二, SQLite 基本使用
1. 建表命令:
create table 表名 (字段名 1 字段类型 1, 字段名 2 字段类型 2, 以此类推....);
create table if not exists (字段名 1 字段类型 1, 字段名 2 字段类型 2, 以此类推 ...) ;
(1)图如下:
(2)代码例子如下:
- - (void)createTable{
- //1. 设计创建表的 sql 语句
- const char *sql = "CREATE TABLE IF NOT EXISTS t_Student(id integer PRIMARY KEY AUTOINCREMENT,name text NOT NULL ,score real DEFAULT 0,sex text DEFAULT'不明');"
- //2. 执行 sql 语句
- int ret = sqlite3_exec(_db, sql, NULL, NULL, NULL);
- //3. 判断执行结果
- if (ret == SQLITE_OK) {
- NSLog(@"创建表成功");
- }else{
- NSLog(@"创建表失败");
- }
- }
2. 插入命令
insert into 表名 (字段 1, 字段 2, 以此类推...) values (字段 1 的值, 字段 2 的值, 以此类推 ...) ;
(1)图如下:
(2)代码如下:
- - (void)insertData{
- //1. 创建插入数据的 sql 语句
- //=========== 插入单条数据 =========
- const char *sql = "INSERT INTO t_Student(name,score,sex)VALUES ('小明',65,'男');";
- //========== 同时插入多条数据 =======
- NSMutableString * mstr = [NSMutableString string];
- for (int i = 0; i <50; i++) {
- NSString * name = [NSString stringWithFormat:@"name%d", i];
- CGFloat score = arc4random() % 101 * 1.0;
- NSString * sex = arc4random() % 2 == 0 ? @"男" : @"女";
- NSString * tsql = [NSString stringWithFormat:@"INSERT INTO t_Student (name,score,sex) VALUES ('%@',%f,'%@');", name, score, sex];
- [mstr appendString:tsql];
- }
- // 将 OC 字符串转换成 C 语言的字符串
- sql = mstr.UTF8String;
- //2. 执行 sql 语句
- int ret = sqlite3_exec(_db, sql, NULL, NULL, NULL);
- //3. 判断执行结果
- if (ret==SQLITE_OK) {
- NSLog(@"插入成功");
- }else{
- NSLog(@"插入失败");
- }
- }
3. 更新命令
update 表名 set 字段 1 = 字段 1 的新值, 字段 2 = 字段 2 的新值, 以此类推 ... ;
4. 删除命令
delete from 表名; 注: 删除的是表中所有记录
拓展: 可以附加一些额外条件删除
条件语句的操作: 可以选择性的删除
- where 字段 = 一个值 ; if(字段 == 某个值) // 不能用两个 =
- where 字段 is 一个值 ; // is 相当于 =
- where 字段 is not 一个值 ; // is not 相当于 !=
- where 字段> 一个值 ;
- where 字段 1 = 一个值 and 字段 2> 一个值 ; // and 相当于 C 语言中的 &&
- where 字段 1 = 一个值 or 字段 2 = 一个值 ; // or 相当于 C 语言中的 ||
(1)图如下:
(2)代码如下:
- - (void)deleteData{
- // 创建删除数据的 sql 语句
- const char *sql = "DELETE FROM t_Student WHERE score <10;";
- // 执行 sql 语句
- int ret = sqlite3_exec(_db, sql, NULL, NULL, NULL);
- // 判断执行结果
- if (ret == SQLITE_OK) {
- NSLog(@"删除成功");
- }else{
- NSLog(@"删除失败");
- }
- }
5. 查询数据
SELECT 字段 1, 字段 2 FROM 表明;
(1)图如下:
(2)代码如下:
- - (void)selectData{
- // 执行数据库语句
- const char *sql = "SELECT name,score FROM t_Student;";
- // 结果集(用来收集结果)
- sqlite3_stmt * stmt;
- int ret = sqlite3_prepare_v2(_db, sql, -1, &stmt, NULL);
- if (ret == SQLITE_OK) {
- NSLog(@"查询成功");
- // 遍历结果集拿到查询到的数据
- //sqlite3_step 获取结果集中的数据
- while (sqlite3_step(stmt) == SQLITE_ROW) {
- // 参数 1: 结果集
- // 参数 2: 列数
- const unsigned char * name = sqlite3_column_text(stmt, 0);
- double score = sqlite3_column_double(stmt, 1);
- NSLog(@"%s %.2lf", name, score);
- }
- }else{
- NSLog(@"查询失败");
- }
- }
三, SQLite 在项目中的使用
对于 SQLite 在项目中, 定义一个单例, 提供一个类方法可以供全局使用, 在编译时初始化这个类, 然后一直保存在内存中, 整个程序就会保持就有一个实例, 在 App 退出时, 系统也会自动释放这个内存.
因为我们定义单例对象针对 SQLite
1, 新建 SQLiteManager
.h 文件
.m 实现
- @interface SQLiteManager()
- @property (nonatomic,assign) sqlite3 *db;
- @end
- @implementation SQLiteManager
- static SQLiteManager *instance;
- + (instancetype)shareInstance{
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- instance = [[self alloc] init];
- });
- return instance;
- }
- // 打开数据库, 返回是布尔值
- - (BOOL)openDB{
- //app 内数据库文件存放路径 - 一般存放在沙盒中
- NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
- NSString *DBPath = [documentPath stringByAppendingPathComponent:@"appDB.sqlite"];
- if (sqlite3_open(DBPath.UTF8String, &_db) != SQLITE_OK) {
- // 数据库打开失败
- return NO;
- }else{
- // 打开成功创建表
- // 用户 表
- NSString *creatUserTable = @"CREATE TABLE IF NOT EXISTS't_User'('ID'INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,'name'TEXT,'age'INTEGER,'icon'TEXT);";
- // 车 表
- NSString *creatCarTable = @"CREATE TABLE IF NOT EXISTS't_Car'('ID'INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,'type'TEXT,'output'REAL,'master'TEXT)";
- // 项目中一般不会只有一个表
- NSArray *SQL_ARR = [NSArray arrayWithObjects:creatUserTable,creatCarTable, nil];
- return [self creatTableExecSQL:SQL_ARR];
- }
- }
- -(BOOL)creatTableExecSQL:(NSArray *)SQL_ARR{
- for (NSString *SQL in SQL_ARR) {
- // 参数一: 数据库对象 参数二: 需要执行的 SQL 语句 其余参数不需要处理
- if (![self execuSQL:SQL]) {
- return NO;
- }
- }
- return YES;
- }
- #pragma 执行 SQL 语句
- - (BOOL)execuSQL:(NSString *)SQL{
- char *error;
- if (sqlite3_exec(self.db, SQL.UTF8String, nil, nil, &error) == SQLITE_OK) {
- return YES;
- }else{
- NSLog(@"SQLiteManager 执行 SQL 语句出错:%s",error);
- return NO;
- }
- }
- #pragma mark - 查询数据库中数据
- -(NSArray *)querySQL:(NSString *)SQL{
- // 准备查询
- // 1> 参数一: 数据库对象
- // 2> 参数二: 查询语句
- // 3> 参数三: 查询语句的长度:-1
- // 4> 参数四: 句柄(游标对象)
- sqlite3_stmt *stmt = nil;
- if (sqlite3_prepare_v2(self.db, SQL.UTF8String, -1, &stmt, nil) != SQLITE_OK) {
- NSLog(@"准备查询失败!");
- return NULL;
- }
- // 准备成功, 开始查询数据
- // 定义一个存放数据字典的可变数组
- NSMutableArray *dictArrM = [[NSMutableArray alloc] init];
- while (sqlite3_step(stmt) == SQLITE_ROW) {
- // 一共获取表中所有列数(字段数)
- int columnCount = sqlite3_column_count(stmt);
- // 定义存放字段数据的字典
- NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
- for (int i = 0; i < columnCount; i++) {
- // 取出 i 位置列的字段名, 作为字典的键 key
- const char *cKey = sqlite3_column_name(stmt, i);
- NSString *key = [NSString stringWithUTF8String:cKey];
- // 取出 i 位置存储的值, 作为字典的值 value
- const char *cValue = (const char *)sqlite3_column_text(stmt, i);
- NSString *value = [NSString stringWithUTF8String:cValue];
- // 将此行数据 中此字段中 key 和 value 包装成 字典
- [dict setObject:value forKey:key];
- }
- [dictArrM addObject:dict];
- }
- return dictArrM;
- }
上面是 SQLite 的工具类封装. 附带 github 地址: https://github.com/zxy1829760/SQLite-.git
上面讲述 SQLite(包含数据库 SQL 语句的基本操作), 大家可以将 git 的工具类直接拖入项目中(如果直接想对 SQLite 封装)-- 当然还有更强大的 FMDB(封装更好 - 目前用的也比较多).
文章一开始说 SQLite 占用资源非常少(红色标注), 下一篇将讲述 SQLite 为什么占用资源非常少?
来源: https://www.cnblogs.com/guohai-stronger/p/9218175.html