IOS中数据存储 sqlite3 的应用
相比于服务器端的数据存储,IOS中几种数据存储的技术:
(1)XML属性列表 —— PList
(2)NSKeyedArchiver 归档
(3)Preference(偏好设置)
(4)SQLite3
(5)Core Data(以面向对象的方式操作数据库SQLite)
发现用数据库进行数据的存储和缓存,才是王道, 比较有心得的体会:虽然通过文件的方式进行存储,读写速度相对数据库存储较快,但是涉及大批量的数据时,在查询/管理/优化方面,数据库的优势明显会更大些.而且作为移动端,SQLite数据库在数据缓存方面的运用则尤为重要.
工作之余,运用SQLite3的许多小知识点,写了一个小小的数据库增删改查操作,专门与sqlite3交互的个人信息管理类,直接上代码,望大牛指正:
底层架构图
核心代码实现:
(1) Services服务层封装
PesonManager.h
#import <Foundation/Foundation.h> #import "Person.h" @interface PersonManager : NSObject + (instancetype)sharedPersonManager; // 1. 新增用户 - (void)addPerson:(Person *)person; // 2. 更新用户(关于主键,永远都不要去修改) - (void)updatePerson:(Person *)person; // 3. 删除用户,使用主键来删除指定用户 - (void)removePerson:(NSInteger)personID; // 4. 列表用户,查询所有用户 - (NSArray *)allPersons; @end
PesonManager.m
#import "PersonManager.h" #import <sqlite3.h> #import "NSString+JH.h" // 全局变量 static PersonManager *_instance; @interface PersonManager() { // 全局的数据库句柄 sqlite3 *_db; } @end @implementation PersonManager #pragma mark - 单例的方法 + (id)allocWithZone:(struct _NSZone *)zone { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [super allocWithZone:zone]; }); return _instance; } + (instancetype)sharedPersonManager { if (_instance == nil) { _instance = [[PersonManager alloc] init]; } return _instance; } #pragma mark - 类方法 - (id)init { self = [super init]; // 懒加载数据库连接及创建数据表 if (self) { // 1. 打开数据库 [self openDB]; // 2. 创建数据表 [self createTable]; } return self; } #pragma mark 打开数据库 - (void)openDB { NSString *dbPath = [@"T_Person.db" appendDocumentDir]; _db = NULL; if (SQLITE_OK == sqlite3_open([dbPath UTF8String], &_db)) { NSLog(@"数据库打开成功"); } else { NSLog(@"数据库打开失败"); } } #pragma mark 单步执行SQL - (void)execSQL:(NSString *)sql message:(NSString *)message { char *errmsg = NULL; if (SQLITE_OK == sqlite3_exec(_db, [sql UTF8String], NULL, NULL, &errmsg)) { NSLog(@"%@成功!", message); } else { NSLog(@"%@失败 - %s", message, errmsg); } } #pragma mark 创建数据表 - (void)createTable { NSString *sql = @"CREATE TABLE IF NOT EXISTS T_Person (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT, gender INTEGER, age INTEGER, height REAL)"; [self execSQL:sql message:@"创建数据表"]; } - (void)addPerson:(Person *)person {
// 1. SQL NSString *sql = [NSString stringWithFormat:@"INSERT INTO T_Person (name, gender, age, height) VALUES ('%@', %d, %d, %f)", person.name, person.gender, person.age, person.height]; [self execSQL:sql message:@"新增个人记录"]; } // 2. 更新用户(关于主键,永远都不要去修改) - (void)updatePerson:(Person *)person where: (NSStirng *)where { NSString *sql = [NSString stringWithFormat:@"UPDATE T_Person SET name = '%@', gender = %d, age = %d, height = %f where %@", person.name, person.gender, person.age, person.height , where]; [self execSQL:sql message:@"更新个人记录"]; } // 3. 删除用户,使用主键来删除指定用户 - (void)removePerson:(NSInteger)personID { NSString *sql =[NSString stringWithFormat: @"delete * from T_Person where id =%@",personID]; [self execSQL:sql message:@"删除记录成功"]; } // 4. 列表用户,查询所有用户 - (NSArray *)allPersons { NSString *sql = @"SELECT id, name, age, gender, height FROM T_Person ORDER BY name"; sqlite3_stmt *stmt = NULL; NSMutableArray *arrayM = [NSMutableArray array]; NSMutableArray *persons = nil; if (SQLITE_OK == sqlite3_prepare_v2(_db, [sql UTF8String], -1, &stmt, NULL)) { persons = [NSMutableArray array]; while (SQLITE_ROW == sqlite3_step(stmt)) { int ID = sqlite3_column_int(stmt, 0); const unsigned char *name = sqlite3_column_text(stmt, 1); int age = sqlite3_column_int(stmt, 2); int gender = sqlite3_column_int(stmt, 3); CGFloat height = sqlite3_column_double(stmt, 4); // const unsigned char *直接输出看不出结果,需要转换 NSString *nameUTF8 = [NSString stringWithUTF8String:(const char *)name]; Person *p = [Person personWithID:ID name:nameUTF8 age:age gender:gender height:height]; [persons addObject:p]; } } else { NSLog(@"语法错误"); } return persons; } @end
接下来在控制器里面封装模型取出相应数据即可,关于SQLite3中运用的知识点,总结如下:
1. sqlite3_open 打开数据库 * 如果数据库已经存在,直接打开 * 如果数据库不存在,新建一个空白的数据库(0KB),然后再打开 2. 创建数据表 * 定义数据操作SQL * 调用sqlite3_exec执行SQL 提示:为了避免重复建表,可以在建表SQL中增加 IF NOT EXISTS 3. 单步执行操作 增/删/改/查数据 4. 查询语句 1> 准备SQL 2> 检查SQL语句是否正确 sqlite3_prepare_v2 3> 单步执行,依次获取查询到的记录 SQLITE_ROW == sqlite3_step... 4> 按照查询顺序,依次取出每一个字段的内容 sqlite3_column_text 取字符串 sqlite3_column_int 取整数 sqlite3_column_double 取浮点数 5.操作SQLite数据库需要5个方法 sqlite3_open sqlite3_exec sqlite3_prepare_v2 sqlite3_step sqlite3_column_text 取字符串 sqlite3_column_int 取整数 sqlite3_column_double 取浮点数 两个枚举 SQLITE_OK SQLITE_ROW
当然,一般在实际开发中都会直接封装成一套数据库操作类,但是对于SQL结构化查询,无论是服务器开发,还是客户端开发,都是万变不离其中.最后,十分感谢大牛LF的讲解与分享.