1. 程式人生 > >iOS-資料持久化之Sqllite

iOS-資料持久化之Sqllite

iOS中的資料儲存方式

Plist(NSArray\NSDictionary) Preference(偏好設定\NSUserDefaults) NSCoding(NSKeyedArchiver\NSkeyedUnarchiver) SQLite3 Core Data     SQLite基礎知識   一、SQLite 1.什麼是SQLite SQLite是一款輕型的嵌入式資料庫 它佔用資源非常的低,在嵌入式裝置中,可能只需要幾百K的記憶體就夠了 它的處理速度比Mysql、PostgreSQL這兩款著名的資料庫都還快   2.什麼是資料庫 資料庫(Database)是按照資料結構來組織、儲存和管理資料的倉庫 資料庫可以分為2大種類 關係型資料庫(主流) 物件型資料庫   3.常用關係型資料庫 PC端:Oracle、MySQL、SQL Server、Access、DB2、Sybase 嵌入式\移動客戶端:SQLite   4.如何儲存資料 資料庫的儲存結構和excel很像,以表(table)為單位   資料庫儲存資料的步驟 新建一張表(table) 新增多個欄位(column,列,屬性) 新增多行記錄(row,每行存放多個欄位對應的值)   二、SQL語句   1.什麼是SQL SQL(structured query language):結構化查詢語言 SQL是一種對關係型資料庫中的資料進行定義和操作的語言 SQL語言簡潔,語法簡單,好學好用   2.什麼是SQL語句 使用SQL語言編寫出來的句子\程式碼,就是SQL語句 在程式執行過程中,要想操作(增刪改查,CRUD)資料庫中的資料,必須使用SQL語句   3.SQL語句的特點 不區分大小寫(比如資料庫認為user和UsEr是一樣的) 每條語句都必須以分號 ; 結尾   4.SQL中的常用關鍵字有 select、insert、update、delete、from、create、where、desc、order、by、group、table、alter、view、index等等   5.資料庫中不可以使用關鍵字來命名錶、欄位     三、SQL語句的種類 1.資料定義語句(DDL:Data Definition Language) 包括create和drop等操作 在資料庫中建立新表或刪除表(create table或 drop table)   2.資料操作語句(DML:Data Manipulation Language) 包括insert、update、delete等操作 上面的3種操作分別用於新增、修改、刪除表中的資料   3.資料查詢語句(DQL:Data Query Language) 可以用於查詢獲得表中的資料 關鍵字select是DQL(也是所有SQL)用得最多的操作 其他DQL常用的關鍵字有where,order by,group by和having   四、DDL 1.創表 格式 create table 表名 (欄位名1 欄位型別1, 欄位名2 欄位型別2, …) ; create table if not exists 表名 (欄位名1 欄位型別1, 欄位名2 欄位型別2, …) ;

 

示例 create table t_student (id integer, name text, age inetger, score real) ;   2.欄位型別 SQLite將資料劃分為以下幾種儲存型別: integer : 整型值 real : 浮點值 text : 文字字串 blob : 二進位制資料(比如檔案)   實際上SQLite是無型別的 就算宣告為integer型別,還是能儲存字串文字(主鍵除外) 建表時宣告啥型別或者不宣告型別都可以,也就意味著創表語句可以這麼寫: create table t_student(name, age);   為了保持良好的程式設計規範、方便程式設計師之間的交流,編寫建表語句的時候最好加上每個欄位的具體型別   3.刪表 格式 drop table 表名 ; drop table if exists 表名 ;

 

示例 drop table t_student ;     五、DML 1.插入資料(insert) 格式 insert into 表名 (欄位1, 欄位2, …) values (欄位1的值, 欄位2的值, …) ;   示例 insert into t_student (name, age) values (‘mj’, 10) ;   注意 資料庫中的字串內容應該用單引號 ’ 括住   2.更新資料(update) 格式 update 表名 set 欄位1 = 欄位1的值, 欄位2 = 欄位2的值, … ;   示例 update t_student set name = ‘jack’, age = 20 ;   注意 上面的示例會將t_student表中所有記錄的name都改為jack,age都改為20   3.刪除資料(delete) 格式 delete from 表名 ;   示例 delete from t_student ;   注意 上面的示例會將t_student表中所有記錄都刪掉     六、條件語句 如果只想更新或者刪除某些固定的記錄,那就必須在DML語句後加上一些條件   條件語句的常見格式 where 欄位 = 某個值 ;   // 不能用兩個 = where 欄位 is 某個值 ;   // is 相當於 = where 欄位 != 某個值 ; where 欄位 is not 某個值 ;   // is not 相當於 != where 欄位 > 某個值 ; where 欄位1 = 某個值 and 欄位2 > 某個值 ;  // and相當於C語言中的 && where 欄位1 = 某個值 or 欄位2 = 某個值 ;  //  or 相當於C語言中的 ||   示例 將t_student表中年齡大於10 並且 姓名不等於jack的記錄,年齡都改為 5 update t_student set age = 5 where age > 10 and name != ‘jack’ ;

 

刪除t_student表中年齡小於等於10 或者 年齡大於30的記錄 delete from t_student where age <= 10 or age > 30 ;   猜猜下面語句的作用 update t_student set score = age where name = ‘jack’ ; 將t_student表中名字等於haha的記錄,height欄位的值 都改為 age欄位的值   七、DQL語句 格式 select 欄位1, 欄位2, … from 表名 ; select * from 表名;   //  查詢所有的欄位   示例 select name, age from t_student ; select * from t_student ; select * from t_student where age > 10 ;  //  條件查詢   八、其他 1.起別名 格式(欄位和表都可以起別名) select 欄位1 別名 , 欄位2 別名 , … from 表名 別名 ; select 欄位1 別名, 欄位2 as 別名, … from 表名 as 別名 ; select 別名.欄位1, 別名.欄位2, … from 表名 別名 ;   示例 select name myname, age myage from t_student ; 給name起個叫做myname的別名,給age起個叫做myage的別名

 

select s.name, s.age from t_student s ; 給t_student表起個別名叫做s,利用s來引用表中的欄位     2.計算記錄的數量 格式 select count (欄位) from 表名 ; select count ( * ) from 表名 ;

 

示例 select count (age) from t_student ; select count ( * ) from t_student where score >= 60;   3.排序 查詢出來的結果可以用order by進行排序 select * from t_student order by 欄位 ; select * from t_student order by age ;   預設是按照升序排序(由小到大),也可以變為降序(由大到小) select * from t_student order by age desc ;  //降序 select * from t_student order by age asc ;   // 升序(預設)   也可以用多個欄位進行排序 select * from t_student order by age asc, height desc ; 先按照年齡排序(升序),年齡相等就按照身高排序(降序)   4.limit 使用limit可以精確地控制查詢結果的數量,比如每次只查詢10條資料   格式 select * from 表名 limit 數值1, 數值2 ;   示例 select * from t_student limit 4, 8 ; 可以理解為:跳過最前面4條語句,然後取8條記錄   limit常用來做分頁查詢,比如每頁固定顯示5條資料,那麼應該這樣取資料 第1頁:limit 0, 5 第2頁:limit 5, 5 第3頁:limit 10, 5 … 第n頁:limit 5*(n-1), 5   猜猜下面語句的作用 select * from t_student limit 7 ; 相當於select * from t_student limit 0, 7 ; 表示取最前面的7條記錄   5.簡單約束 建表時可以給特定的欄位設定一些約束條件,常見的約束有 not null :規定欄位的值不能為null unique :規定欄位的值必須唯一 default :指定欄位的預設值

(建議:儘量給欄位設定嚴格的約束,以保證資料的規範性)

  示例 create table t_student (id integer, name text not null unique, age integer not null default 1) ; name欄位不能為null,並且唯一 age欄位不能為null,並且預設為1   6.主鍵約束 如果t_student表中就name和age兩個欄位,而且有些記錄的name和age欄位的值都一樣時,那麼就沒法區分這些資料,造成資料庫的記錄不唯一,這樣就不方便管理資料   良好的資料庫程式設計規範應該要保證每條記錄的唯一性,為此,增加了主鍵約束 也就是說,每張表都必須有一個主鍵,用來標識記錄的唯一性   什麼是主鍵 主鍵(Primary Key,簡稱PK)用來唯一地標識某一條記錄 例如t_student可以增加一個id欄位作為主鍵,相當於人的身份證 主鍵可以是一個欄位或多個欄位   7.主鍵的設計原則 主鍵應當是對使用者沒有意義的   永遠也不要更新主鍵   主鍵不應包含動態變化的資料   主鍵應當由計算機自動生成   8.主鍵的宣告 在創表的時候用primary key宣告一個主鍵 create table t_student (id integer primary key, name text, age integer) ; integer型別的id作為t_student表的主鍵   主鍵欄位 只要宣告為primary key,就說明是一個主鍵欄位 主鍵欄位預設就包含了not null 和 unique 兩個約束   如果想要讓主鍵自動增長(必須是integer型別),應該增加autoincrement create table t_student (id integer primary key autoincrement, name text, age integer) ;   9.外來鍵約束 利用外來鍵約束可以用來建立表與表之間的聯絡 外來鍵的一般情況是:一張表的某個欄位,引用著另一張表的主鍵欄位   新建一個外來鍵 create table t_student (id integer primary key autoincrement, name text, age integer, class_id integer, constraint fk_t_student_class_id_t_class_id foreign key (class_id) (id)) ; references t_class t_student表中有一個叫做fk_t_student_class_id_t_class_id的外來鍵 這個外來鍵的作用是用t_student表中的class_id欄位引用t_class表的id欄位   10.表連線查詢 什麼是表連線查詢 需要聯合多張表才能查到想要的資料   表連線的型別 內連線:inner join 或者 join  (顯示的是左右表都有完整欄位值的記錄) 左外連線:left outer join (保證左表資料的完整性)   示例 查詢0316iOS班的所有學生 select s.name,s.age from t_student s, t_class c where s.class_id = c.id and c.name = ‘0316iOS’;    

OS開發資料庫篇—SQLite常用的函式

一、簡單說明

1.開啟資料庫

int sqlite3_open(

    const char *filename,   // 資料庫的檔案路徑

    sqlite3 **ppDb          // 資料庫例項

);

 

2.執行任何SQL語句

int sqlite3_exec(

    sqlite3*,                                  // 一個開啟的資料庫例項

    const char *sql,                           // 需要執行的SQL語句

    int (*callback)(void*,int,char**,char**),  // SQL語句執行完畢後的回撥

    void *,                                    // 回撥函式的第1個引數

    char **errmsg                              // 錯誤資訊

);

 

3.檢查SQL語句的合法性(查詢前的準備)

int sqlite3_prepare_v2(

    sqlite3 *db,            // 資料庫例項

    const char *zSql,       // 需要檢查的SQL語句

    int nByte,              // SQL語句的最大位元組長度

    sqlite3_stmt **ppStmt,  // sqlite3_stmt例項,用來獲得資料庫資料

    const char **pzTail

);

 

4.查詢一行資料

int sqlite3_step(sqlite3_stmt*); // 如果查詢到一行資料,就會返回SQLITE_ROW

 

5.利用stmt獲得某一欄位的值(欄位的下標從0開始)

double sqlite3_column_double(sqlite3_stmt*, int iCol);  // 浮點資料

int sqlite3_column_int(sqlite3_stmt*, int iCol); // 整型資料

sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); // 長整型資料

const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); // 二進位制文字資料

const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);  // 字串資料

 

二、SQLite編碼

1.建立、開啟、關閉資料庫

建立或開啟資料庫

// path是資料庫檔案的存放路徑

sqlite3 *db = NULL;

int result = sqlite3_open([path UTF8String], &db); 

 

程式碼解析:

sqlite3_open()將根據檔案路徑開啟資料庫,如果不存在,則會建立一個新的資料庫。如果result等於常量SQLITE_OK,則表示成功開啟資料庫

sqlite3 *db:一個開啟的資料庫例項

資料庫檔案的路徑必須以C字串(而非NSString)傳入

 

關閉資料庫:sqlite3_close(db);

 

2.執行不返回資料的SQL語句

執行創表語句

char *errorMsg = NULL;  // 用來儲存錯誤資訊

char *sql = "create table if not exists t_person(id integer primary key autoincrement, name text, age integer);";

int result = sqlite3_exec(db, sql, NULL, NULL, &errorMsg);

 

程式碼解析:

sqlite3_exec()可以執行任何SQL語句,比如創表、更新、插入和刪除操作。但是一般不用它執行查詢語句,因為它不會返回查詢到的資料

sqlite3_exec()還可以執行的語句:

(1)開啟事務:begin transaction;

(2)回滾事務:rollback;

(3)提交事務:commit;

 

3.帶佔位符插入資料

char *sql = "insert into t_person(name, age) values(?, ?);";

sqlite3_stmt *stmt;

if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) == SQLITE_OK) {

    sqlite3_bind_text(stmt, 1, "母雞", -1, NULL);

    sqlite3_bind_int(stmt, 2, 27);

}

if (sqlite3_step(stmt) != SQLITE_DONE) {

    NSLog(@"插入資料錯誤");

}

sqlite3_finalize(stmt);

 

程式碼解析:

sqlite3_prepare_v2()返回值等於SQLITE_OK,說明SQL語句已經準備成功,沒有語法問題

sqlite3_bind_text():大部分繫結函式都只有3個引數

(1)第1個引數是sqlite3_stmt *型別

(2)第2個引數指佔位符的位置,第一個佔位符的位置是1,不是0

(3)第3個引數指佔位符要繫結的值

(4)第4個引數指在第3個引數中所傳遞資料的長度,對於C字串,可以傳遞-1代替字串的長度

(5)第5個引數是一個可選的函式回撥,一般用於在語句執行後完成記憶體清理工作

sqlite_step():執行SQL語句,返回SQLITE_DONE代表成功執行完畢

sqlite_finalize():銷燬sqlite3_stmt *物件

 

4.查詢資料

char *sql = "select id,name,age from t_person;";

sqlite3_stmt *stmt;

if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) == SQLITE_OK) {

    while (sqlite3_step(stmt) == SQLITE_ROW) {

        int _id = sqlite3_column_int(stmt, 0);

        char *_name = (char *)sqlite3_column_text(stmt, 1);

        NSString *name = [NSString stringWithUTF8String:_name];

        int _age = sqlite3_column_int(stmt, 2);

        NSLog(@"id=%i, name=%@, age=%i", _id, name, _age);

    }

}

sqlite3_finalize(stmt);

程式碼解析:

sqlite3_step()返回SQLITE_ROW代表遍歷到一條新記錄

sqlite3_column_*()用於獲取每個欄位對應的值,第2個引數是欄位的索引,從0開始

     我的程式碼 複製程式碼

//
// ViewController.m
// IOS_0331_SQLite3
//
// Created by ma c on 16/3/31.
// Copyright © 2016年 博文科技. All rights reserved.
//

#import "ViewController.h"
#import <sqlite3.h>

@interface ViewController ()
- (IBAction)insert;
- (IBAction)update;
- (IBAction)query;
- (IBAction)delete;

@end

@implementation ViewController
{
// db代表整個資料庫,db是資料庫例項
sqlite3 *_db;
}

- (void)viewDidLoad {
[super viewDidLoad];

[self createDatabase];
}

- (void)createDatabase
{
// 0.獲得沙盒中的資料庫檔名
NSString *fileName = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"student.sqlite"];
NSLog(@"%@",fileName);

// 2.建立(開啟)資料庫(如果資料庫檔案不存在會自動建立)
int result = sqlite3_open(fileName.UTF8String, &_db);

if (result == SQLITE_OK) {
NSLog(@"成功開啟資料庫");
// 3.創表
const char *sql = "create table if not exists t_student (id integer primary key autoincrement, name text, age integer);";
char *error = NULL;
int result = sqlite3_exec(_db, sql, NULL, NULL, &error);

if (result == SQLITE_OK) {
NSLog(@"成功建立表");
} else {
NSLog(@"建立表失敗");
}

} else {
NSLog(@"開啟資料庫失敗");
}
}

- (IBAction)insert {
const char *sql = "insert into t_student (name, age) values ('jack', 20);";

int result = sqlite3_exec(_db, sql, NULL, NULL, NULL);

if (result == SQLITE_OK) {
NSLog(@"成功插入資料");
} else {
NSLog(@"插入資料失敗");
}

}

- (IBAction)update {
}

- (IBAction)query {

//1.定義sql語句
const char *sql = "select id, name, age from t_student where name = ?;";
//2.定義一個stmt存放結果集
sqlite3_stmt *stmt = NULL;
//3.檢查sql語句合法性
int result = sqlite3_prepare_v2(_db, sql, -1, &stmt, NULL);
if (result == SQLITE_OK) {
NSLog(@"查詢語句是合法的");
//設定佔位符內容
sqlite3_bind_text(stmt, 1, "jack", -1, NULL);

//4.執行sql語句
while (sqlite3_step(stmt) == SQLITE_ROW) {
//獲得這行對應的資料

int sid = sqlite3_column_int(stmt, 0);

const unsigned char *sname = sqlite3_column_text(stmt, 1);

int sage = sqlite3_column_int(stmt, 2);

NSLog(@"%d %s %d",sid, sname, sage);
}
} else {
NSLog(@"查詢語句非法");
}
}

- (IBAction)delete {
}
@end

複製程式碼