iOS - 使用 SQLite 数据库实现数据持久化
前言
SQLite 是一款主流的嵌入式關(guān)系型數(shù)據(jù)庫,它的主要特點是輕量級和跨平臺,是當(dāng)前很多嵌入式操作系統(tǒng)中數(shù)據(jù)庫的首選。
數(shù)據(jù)庫也是客戶端開發(fā)中常用的一種數(shù)據(jù)持久化手段,本文主要介紹在客戶端開發(fā)中常用的數(shù)據(jù)庫 SQLite,結(jié)合一個簡單的理解講解它引入、創(chuàng)建到后面 CRUD 的操作。
文章目錄
- 前言
- 1. sqlite3 引入
- 2. sqlite3 的使用
- 2.1 VGUserDAO 的封裝
- 2.2 建表操作
- 2.3 查詢操作
- 2.4 插入操作
- 2.5 修改操作
- 2.6 刪除操作
- 參考資料
1. sqlite3 引入
要想在 iOS 開發(fā)中使用 SQLite 數(shù)據(jù)庫,先要導(dǎo)入 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;@end2.1 VGUserDAO 的封裝
為了滿足我們的需求,我們封裝一個 VGUserDAO 類來實現(xiàn)我們要的操作,主要實現(xiàn)下面方法:
@interface VGUserDAO : NSObject/// 獲取 VGUserDAO 單例 + (instancetype)sheredInstance;/// 查找特定ID的用戶 - (VGUser *)findById:(NSString *)userId;/// 查詢所有用戶 - (NSArray *)findAll;/// 在數(shù)據(jù)表中插入一行數(shù)據(jù) - (void)create:(VGUser *)user;/// 刪除特定ID的用戶 - (void)remove:(NSString *)userId;/// 修改用戶信息 - (void)modify:(VGUser *)user;@endVGUserDAO.m 文件的部分代碼
#import "VGUser.h" #import <sqlite3.h>#define DBFILE_NAME @"UserList.sqlite3"@interface VGUserDAO () {sqlite3 *_db; // 數(shù)據(jù)庫對象 }// 數(shù)據(jù)庫的存儲路徑 @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];// 設(shè)置數(shù)據(jù)庫的存儲路徑sharedInstance.plistFilePath = [sharedInstance applicationDocumentsDirectory];// 執(zhí)行檢表操作[sharedInstance createEditableDatabaseIfNeed];});return sharedInstance; }// 獲取數(shù)據(jù)庫的存儲路徑 - (NSString *)applicationDocumentsDirectory {NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, TRUE) lastObject];NSString *path = [docDir stringByAppendingPathComponent:DBFILE_NAME];return path; }//......@end2.2 建表操作
建表操作主要包含以下幾個步驟:
- 使用 sqlite3_open 函數(shù)打開數(shù)據(jù)庫
- 使用 sqlite3_exec 函數(shù)執(zhí)行建表的 SQL 語句,創(chuàng)建用戶表
- 使用 sqlite3_close 函數(shù)關(guān)閉數(shù)據(jù)庫,釋放資源
具體的代碼實現(xiàn)如下:
- (void)createEditableDatabaseIfNeed {const char *cpath = self.plistFilePath.UTF8String;// sqlite3_open// 1. filename 是數(shù)據(jù)庫文件的完整路徑// 2. ppDb 是sqlite3類型指針變量的地址if (sqlite3_open(cpath, &_db) != SQLITE_OK) {NSLog(@"數(shù)據(jù)庫打開失敗");} 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類型指針變量,表示數(shù)據(jù)庫// 2. sql 是要執(zhí)行的sql語句// 3. 要回調(diào)的函數(shù)指針// 4. 要回調(diào)的函數(shù)的第一個參數(shù)// 5. 執(zhí)行出錯信息的字符串if (sqlite3_exec(_db, cSql, NULL, NULL, NULL) != SQLITE_OK) {NSLog(@"建表失敗");}}// 關(guān)閉數(shù)據(jù)庫sqlite3_close(_db); }建表的時候需要指定數(shù)據(jù)類型,SQLite 支持的常見數(shù)據(jù)類型如下所示:
- integer,有符號的整數(shù)類型
- real,浮點數(shù)
- text,字符串類型,采用 UTF-8 和 UTF-16 編碼
- blob,二進制大對象類型,能夠存放任何二進制數(shù)據(jù)
2.3 查詢操作
使用 sqlite3 執(zhí)行查詢操作,主要包括如下步驟:
- 使用 sqlite3_open 函數(shù)打開數(shù)據(jù)庫
- 使用 sqlite3_prepare_v2 函數(shù)預(yù)處理 SQL 語句
- 使用 sqlite3_bind_text 等函數(shù)綁定參數(shù)
- 使用 sqlite3_step 函數(shù)執(zhí)行 SQL 語句
- 使用 sqlite3_column_text 等函數(shù)提取結(jié)果集中的字段
- 使用 sqlite3_finalize 和 sqlite3_close 函數(shù)釋放資源
下面是對根據(jù) ID 查詢特定用戶的方法的實現(xiàn):
- (VGUser *)findById:(NSString *)userId {const char *cpath = self.plistFilePath.UTF8String;if (sqlite3_open(cpath, &_db) != SQLITE_OK) {NSLog(@"數(shù)據(jù)庫打開失敗");} 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預(yù)處理函數(shù)// 1. db 是sqlite3類型指針變量,表示數(shù)據(jù)庫// 2. zSql 是要執(zhí)行的SQL語句// 3. nByte 是全部SQL字符串的最大長度// 4. ppStmt 是sqlite3_stmt類型指針的地址,表示語句對象// 5. pzTail 是zSql沒有執(zhí)行部分if (sqlite3_prepare_v2(_db, cSql, -1, &statement, NULL) == SQLITE_OK) {const char *cUserId = userId.UTF8String;// sqlite3_bind_text 綁定SQL語句TEXT類型的參數(shù)// 1. sqlite3_stmt類型指針// 2. 參數(shù)的序號,從 1 開始// 3. 參數(shù)的值// 4. 字符串長度// 5. 函數(shù)指針sqlite3_bind_text(statement, 1, cUserId, -1, NULL);// sqlite3_step 執(zhí)行語句if (sqlite3_step(statement) == SQLITE_ROW) {// sqlite3_column_text 讀取字符串類型數(shù)據(jù)// 1. 語句對象// 2. SELECT字段的索引,從 0 開始char *bufUserId = (char *)sqlite3_column_text(statement, 0);char *bufUserName = (char *)sqlite3_column_text(statement, 1);// sqlite3_column_int 讀取int類型數(shù)據(jù)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; }下面是對查找所有用戶的方法的實現(xiàn):
- (NSArray *)findAll {const char *cpath = self.plistFilePath.UTF8String;NSMutableArray *userList = [NSMutableArray array];if (sqlite3_open(cpath, &_db) != SQLITE_OK) {NSLog(@"數(shù)據(jù)庫打開失敗");} 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 表示結(jié)果集中還有數(shù)據(jù)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]; }在進行字段讀取的時候,根據(jù)字段類型的不同,有下面幾種常用函數(shù):
- sqlite3_column_int()
- sqlite3_column_int64()
- sqlite3_column_double()
- sqlite3_column_text()
- sqlite3_column_text16()
- sqlite3_column_blob()
我們可以根據(jù)字段的類型,選擇合適的函數(shù)。參數(shù)綁定函數(shù) sqlite3_bind_text 也是同理。
2.4 插入操作
使用 sqlite3 執(zhí)行插入操作,主要包含如下步驟:
- 使用 sqlite3_open 函數(shù)打開數(shù)據(jù)庫
- 使用 sqlite3_prepare_v2 函數(shù)預(yù)處理 SQL 語句
- 使用 sqlite3_bind_text 等函數(shù)綁定參數(shù)
- 使用 sqlite3_step 函數(shù)執(zhí)行 SQL 語句
- 使用 sqlite3_finalize 和 sqlite3_close 函數(shù)釋放資源
2.5 修改操作
對與修改操作而言,已經(jīng)沒有新東西可言了,主要差別還是在 SQL 語句,插入、修改和刪除用的分別是 insert、 update 和 delete。
- (void)modify:(VGUser *)user {const char *cpath = self.plistFilePath.UTF8String;if (sqlite3_open(cpath, &_db) != SQLITE_OK) {NSLog(@"數(shù)據(jù)庫打開失敗");} 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(@"數(shù)據(jù)修改失敗");}}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(@"數(shù)據(jù)庫打開失敗");} 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(@"數(shù)據(jù)刪除失敗");}}sqlite3_finalize(statement);}sqlite3_close(_db); }參考資料
- 《iOS開發(fā)指南:從Hello World到App Store上架(第5版)》
總結(jié)
以上是生活随笔為你收集整理的iOS - 使用 SQLite 数据库实现数据持久化的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iOS - 沙盒文件操作指南
- 下一篇: iOS - 数据持久化之 FMDB 的使