SQLite數據庫

SQLite是遵守ACID的關系數據庫管理系統,它包含在一個相對小的C程序庫中。與許多其它數據庫管理系統不同,SQLite不是一個客戶端/服務器結構的數據庫引擎,而是被集成在用戶程序中。-------維基百科

  • 數據庫簡介
  • Navicat的使用
  • Navicat的演練
    • SQL語句之數據定義語句
    • SQL語句之數據操作語句
    • SQL語句之數據查詢語句
  • Xcode原聲SQLite演練
    • 創建數據庫和表
    • 增刪改
    • 查詢
  • FMDB
    • FMDB增刪改查演練

數據庫簡介

  • 數據庫的作用:離線緩存數據
  • 數據緩存策略:plist,歸檔,偏好設置,沙盒文件,SQLite數據
  • 系統提供的數據存儲方式的弊端
    • 不方便操作大量的數據
      • 如果要添加新的數據,必須先把舊數據全部加載到內存中 * 系統提供的數據存儲方式都是覆蓋存儲的,新的數據會覆蓋舊的數據
    • 不方便查找大量的數據
      • 當數據量非常龐大時,要查詢其中某些數據,就非常困難
    • 比如把數組數據存儲到plist文件中,當數據量比較大時,無論存儲還是查找數據都相當不方便
      • 當plist文件中的數據量非常龐大時,一次性加載到內存,會造成內存暴漲
      • 當plist文件中的數據量非常龐大時,要查詢其中的某一條數據時非常困難
  • SQLite簡介
    • SQLite是一款輕量級數據庫
      • 設計目標是嵌入式的(可以放在手機沙盒里面的)
      • 體積小,占用資源少
      • 處理速度快
      • 跨平臺
    • 客戶端的數據庫 : SQLite
    • 服務器端的數據庫 : MySQL , SQLServer , Oracle
  • SQLite數據庫學習方法
    • 先用Navicat客戶端演示SQLite的使用,并檢查效果
    • 再用代碼演示SQLite的使用

Navicat的使用

提示 : 數據庫本身就是一個文件,可以用客戶端來操作,實際開發是在Xcode中寫SQL語句實現數據庫的增刪改查

  • Navicat創建數據庫文件和數據庫表
    • Navicat創建數據庫和表的步驟
      • 1.創建一個數據庫文件,以".sqlite"結尾
      • 2.建立Navicat和數據庫文件的連接,只有建立好連接才能操作數據庫文件
      • 3.創建數據庫表,創建表頭(字段名),并指定數據類型
      • 4.保存數據庫文件,以"t_xxx"命名
  • Navicat操作數據 - 增刪改查
    • 在數據庫中
      • 行 : 記錄/數據 (一條記錄/一條數據)
      • 列 : 字段名/列名
    • 增刪改查操作
      • 新增 : '+'
      • 刪除 : '-'
      • 修改 : 雙擊字段直接修改
      • 查詢 : 'filter' (過濾)

Navicat演練SQL語句

  • SQL語句之數據定義語句

以商品表為例 t_product。 創建 create 和刪除 drop 數據庫表

  • 創建數據庫表
    • 如果數據庫表不存在,就創建一個
    • 創建字段名的同時制定字段類型
    • create table if not exists 表名(字段名1 類型,字段名2 類型,...);
      • create table if not exists t_product(productID integer,productName text,productPrice integer);
  • 刪除數據庫表
    • 如果數據庫表存在再刪除
SQL語句之數據操作語句

以商品表為例 t_product。 數據操作語句包括 : 增 , 刪 , 改;

  • 新增語句:insert into 表名 (字段名1,字段名2,...) values (字段1值,字段2值,...);

    • 每個字段都有值的請情況:insert into t_product(productID,productName,productPrice) values(100,'iPhone100',100);
    • 部分字段有值的情況:insert into t_product(productID,productName) values(101,'iPhone101');
    • 注意:字符串用'單引號'引起來
  • 修改語句:update 表名 set 字段名 = 新值 where 條件語句

    • 當沒有條件時,表里面所有的productPrice字段的值都會變成101:update t_product set productPrice = 101;
    • 按照條件修改一個字段的值:update t_product set productPrice = 101 where productID = 101;
    • 按照條件,修改一條記錄的多個字段的值:update t_product set productName = 'iPhone102',productPrice = 102 where productID = 101;
  • 刪除語句:delete from 表名 where 條件語句;

    • 按照條件刪除一條記錄:delete from t_product where productID = 101;
    • 注意:如果執行刪除語句時不加條件語句,就會刪除表中所有的記錄
  • 總結

    • 數據操作語句分為 : 新增語句,刪除語句,修改語句
    • 新增語句里面沒有條件語句,刪除和修改語句里面有條件語句
    • 刪除語句 + 條件語句 = 表示刪除哪些記錄
    • 修改語句 + 條件語句 = 表示修改哪些記錄
    • 條件語句不能單獨存在,他必須接在 刪除語句 / 修改語句 / 查詢語句后面

Xcode原聲SQLite演練

創建數據庫和表
  • 使用準備

    • 導入頭文件#import <sqlite3.h>
    • 新增類庫libsqlite3.0.tbd
  • 使用步驟

    • 1.準備數據庫存儲的路徑
    • 2.創建數據庫文件并打開
    • 3.如果創建數據庫文件成功,就創建數據庫表
    • 4.創建數據庫表成功就可以操作數據庫 (增刪改查)
  • 提示

    • sqlite3中的函數都是以sqlite3開頭的
    • 創建并打開數據庫函數 : sqlite3_open
    • 建表和數據操作函數(查詢函數除外) : sqlite3_exec
    • 查詢函數 : sqlite3_prepare_v2
    • 查詢數據時會得到結果集,要查詢的數據都在結果集中,while循環遍歷結果集一條一條記錄取出來
  • 函數說明

創建數據庫文件的函數

/*
參數1 : 數據庫的存儲路徑
參數2 : 數據庫實例
返回值 : int
*/
sqlite3_open(<#const char *filename#>, <#sqlite3 **ppDb#>);


創建數據庫表的函數

/*
參數1 : 數據庫實例
參數2 : 要執行的SQL語句(建表)
參數3 : 建表成功的回調,傳入NULL
參數4 : 回調的參數,傳入NULL
參數5 : 錯誤信息
*/
sqlite3_exec(<#sqlite3 *#>, <#const char *sql#>, <#int (*callback)(void *, int, char **, char **)#>, <#void *#>, <#char **errmsg#>);

  • 創建數據庫和表

全局的數據庫實例

{
    sqlite3 *_db;
}

創建數據庫的函數sqlite3_open

/// 創建數據庫
- (void)createDB
{
    /*
     創建并打開數據庫
     這個函數會自動監測數據庫是否已經存在,只有在數據庫不存的時候才會去新建數據庫并打開數據庫

     參數1 : 數據庫的路徑
     參數2 : 數據庫實例

     返回值 int
    */

    // 1.數據庫路徑
    NSString *SQLPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"SQL.db"];
    // 2.創建并打開數據庫的函數
    int result = sqlite3_open(SQLPath.UTF8String, &_db);
    // 判斷數據庫是否創建打開成功
    if (result == SQLITE_OK) {
        NSLog(@"數據庫創建打開成功");

        /*
         建表

         參數1 : 數據庫實例
         參數2 : 建表的SQL語句
         參數3 : 函數執行成功的回調,不需要就寫NULL
         參數4 : 回調的參數,沒有就寫NULL
         參數5 : 保存錯誤信息

         返回值 int
         */

        // 3.建表SQL語句
        NSString *createSQL = @"create table if not exists t_person(id integer primary key,name text not null,age integer);";
        // 保存錯誤信息
        char *errmsg = NULL;

        sqlite3_exec(_db, createSQL.UTF8String, NULL, NULL, &errmsg);
        if (errmsg == nil) {
            NSLog(@"建表成功");
        }
    }

    // 4.操作表
}


增刪改
  • 新增記錄
- (void)insert
{
    // 新增SQL語句
    NSString *insertSQL = @"insert into t_person(name,age) values('老王',21);";
    // 保存錯誤信息
    char *errmsg = NULL;

    sqlite3_exec(_db, insertSQL.UTF8String, NULL, NULL, &errmsg);
    if (errmsg == nil) {

        // 獲取影響的行數
        int changes = sqlite3_changes(_db);
        NSLog(@"insert影響的行數 %d",changes);

        NSLog(@"新增成功");
    }
}

  • 刪除記錄

刪除記錄時,如果數據不存在,不會返回錯誤

- (void)delete
{
    // 刪除SQL語句
    NSString *deleteSQL = @"delete from t_person where id = 4;";
    // 保存錯誤信息
    char *errmsg = NULL;

    sqlite3_exec(_db, deleteSQL.UTF8String, NULL, NULL, &errmsg);
    if (errmsg == nil) {

        // 獲取影響的行數
        int changes = sqlite3_changes(_db);
        NSLog(@"delete影響的行數 %d",changes);

        NSLog(@"刪除成功");
    }
}

  • 修改記錄

更新記錄時,如果指定的 id 不存在,不會返回錯誤

- (void)update
{
    // 修改SQL語句
    NSString *updateSQL = @"update t_person set name = '李雷' where id = 2;";
    // 保存錯誤信息
    char *errmsg = NULL;

    sqlite3_exec(_db, updateSQL.UTF8String, NULL, NULL, &errmsg);
    if (errmsg == nil) {

        // 獲取影響的行數
        int changes = sqlite3_changes(_db);
        NSLog(@"update影響的行數 %d",changes);

        NSLog(@"修改成功");
    }
}

  • 小結
    • 新增 / 修改 / 刪除本質上都是執行一個 SQL
    • 新增記錄可以使用 sqlite3_last_insert_rowid 獲取最后插入的主鍵數值
    • 更新 / 刪除記錄可以使用 sqlite3_changes 獲取影響數據行數
    • 在開發數據庫功能時,最容易出錯的位置是 SQL 語句的錯誤,而不是代碼錯誤,一定要利用 navicat 協助檢查語法
查詢
  • 預編譯 : 檢查SQL語法的有效性

- (void)query
{
    /*
     執行查詢語句

     參數1 : 數據庫實例
     參數2 : 查詢語句
     參數3 : 查詢語句的長度,傳入-1,讓函數自己算
     參數4 : 結果集,遍歷結果集,取數據
     參數5 : 一般傳入NULL

     返回值 int
     */

    // 查詢SQL語句
    NSString *querySQL = @"select name,age from t_person;";
    // 結果集
    sqlite3_stmt *ppStmt = NULL;
    // 執行查詢語句
    int result = sqlite3_prepare_v2(_db, querySQL.UTF8String, -1, &ppStmt, NULL);
    // 預編譯 : 檢查語法的有效性
    if (result == SQLITE_OK) {
        NSLog(@"查詢數據失敗");
    } else {
        NSLog(@"查詢數據失敗");
    }

    // 釋放結果集 : 不然會內存泄露
    sqlite3_finalize(ppStmt);
}

  • 執行查詢操作
- (void)query
{
    /*
     執行查詢語句

     參數1 : 數據庫實例
     參數2 : 查詢語句
     參數3 : 查詢語句的長度,傳入-1,讓函數自己算
     參數4 : 結果集,遍歷結果集,取數據
     參數5 : 一般傳入NULL

     返回值 int
     */

    // 查詢SQL語句
    NSString *querySQL = @"select name,age from t_person;";
    // 結果集
    sqlite3_stmt *ppStmt = NULL;
    // 執行查詢語句
    int result = sqlite3_prepare_v2(_db, querySQL.UTF8String, -1, &ppStmt, NULL);
    // 預編譯 : 檢查語法的有效性
    if (result == SQLITE_OK) {

        // 遍歷結果集,逐條取數據,直到往下找,找不到數據為止
        while (sqlite3_step(ppStmt) == SQLITE_ROW) {

            /*
             參數1 : 結果集
             參數2 : 字段的索引,從主鍵后面開始計數
             */

            // 取name
            const unsigned char *cName = sqlite3_column_text(ppStmt, 0);
            NSString *ocName = [[NSString alloc] initWithCString:(const char *)cName encoding:NSUTF8StringEncoding];
            // 取age
            int age = sqlite3_column_int(ppStmt, 1);

            NSLog(@"%@ -- %d",ocName,age);
        }

    } else {
        NSLog(@"查詢數據失敗");
    }

    // 釋放結果集 : 不然會內存泄露
    sqlite3_finalize(ppStmt);
}

  • 小結
    • sqlite3_prepare_v2 對 SQL 語句進行預編譯,并且檢查是否存在語法問題
    • 編譯成功后通過 sqlite3_step 執行 SQL,每執行一次,獲取一條記錄
    • 通過 while 循環直至執行完畢
    • 注意,指令執行完畢后需要釋放 sqlite3_finalize(ppStmt)

FMDB

FMDB增刪改查演練
  • 準備工作

    • 導入頭文件 #import "FMDB.h"
    • 操作的類 FMDatabase 單線程時使用
    • 全局的靜態數據庫對象 static FMDatabase *_db;
  • 創建數據庫和表

數據庫的創建和建表只需要執行一次

initialize : 這個類在第一次使用時就被調用一次,后面就不會再調用;而且是先于實例化方法調用的

+ (void)initialize
{
//    NSLog(@"這個類在第一次使用時就被調用一次");

    // 1.獲取數據庫路徑
    NSString *SQLPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"heros.db"];

    // 2.創建數據庫和建表,只會執行一次
    _db = [FMDatabase databaseWithPath:SQLPath];

    // 3.打開數據庫
    BOOL isOpen = [_db open];
    if (isOpen) {
        // 4.建表
        BOOL isCreate = [_db executeUpdate:@"create table if not exists t_heros(id integer primary key,name text not null,age integer)"];
        if (isCreate) {
            NSLog(@"建表成功");
        }
    }
}


  • 新增
    • [_db executeUpdateWithFormat:@"insert into t_heros(name,age) values('張三',18)"];
  • 修改
    • [_db executeUpdateWithFormat:@"update t_heros set age = 19 where name = '張三'"];
  • 刪除
    • [_db executeUpdateWithFormat:@"delete from t_heros where name = '張三'"];
  • 查詢--模糊查詢
// 執行查詢語句.獲取到結果集
FMResultSet *resultSet = [_db executeQuery:@"select * from t_heros"];

// 遍歷結果集,取數據
while ([resultSet next]) {

    // 取出來的數據
    NSString *name = [resultSet stringForColumn:@"name"];
    int age = [resultSet intForColumn:@"age"];
}

  • 如果數據庫里面的記錄有很多條
+ (NSArray *)selectHeros
{
    // 定義臨時的模型數據
    NSMutableArray *tmpM = [NSMutableArray array];

    // 執行查詢語句.獲取到結果集
    FMResultSet *resultSet = [_db executeQuery:@"select * from t_heros"];

    // 遍歷結果集,取數據
    while ([resultSet next]) {

        // 創建模型
        Heros *hero = [[Heros alloc] init];

        // 取出來的數據
        NSString *name = [resultSet stringForColumn:@"name"];
        int age = [resultSet intForColumn:@"age"];

        // 給模型賦值
        hero.name = name;
        hero.age = @(age);

        // 將模型添加到模型數組
        [tmpM addObject:hero];
    }

    return tmpM.copy;
}

感謝讀到最后的朋友,最后祝大家工作順利,請點贊支持一下,謝謝!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容