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, …) ;
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