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是一款輕量級數據庫
-
SQLite數據庫學習方法
先用Navicat客戶端演示SQLite的使用,并檢查效果
再用代碼演示SQLite的使用
Navicat的使用
提示 : 數據庫本身就是一個文件,可以用客戶端來操作,實際開發是在Xcode中寫SQL語句實現數據庫的增刪改查
-
Navicat創建數據庫文件和數據庫表
- Navicat創建數據庫和表的步驟
1.創建一個數據庫文件,以".sqlite"結尾
2.建立Navicat和數據庫文件的連接,只有建立好連接才能操作數據庫文件
3.創建數據庫表,創建表頭(字段名),并指定數據類型
4.保存數據庫文件,以"t_xxx"命名
- Navicat創建數據庫和表的步驟
-
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;
- 當沒有條件時,表里面所有的productPrice字段的值都會變成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;
}
感謝讀到最后的朋友,最后祝大家工作順利,請點贊支持一下,謝謝!