一.SQLite的介紹
1.為什么要存儲數(shù)據(jù)?
1.1 手機(jī)數(shù)據(jù)大多都是從網(wǎng)絡(luò)加載的,不存儲,每次滾動界面都要從新發(fā)送網(wǎng)絡(luò)請求加載數(shù)據(jù),浪費(fèi)流量
1.2 當(dāng)用戶沒網(wǎng)的時候,就不能正常顯示界面了
1.3 將數(shù)據(jù)存儲到本地,不用每次加載,沒網(wǎng)的時候也可從本地存儲的數(shù)據(jù)拿來顯示
2.存儲數(shù)據(jù)的方式
Plist(NSArray\NSDictionary)
特點(diǎn): 只能存儲系統(tǒng)自帶的數(shù)據(jù)類型, 比如NSDictory, NSArray等等. 自定義的對象無法存儲Preference(偏好設(shè)置\NSUserDefaults)
特點(diǎn): 本質(zhì)就是一個plist文件; 也是只能存儲系統(tǒng)自帶的數(shù)據(jù)類型, 自定義的對象無法存儲NSCoding(NSKeyedArchiver\NSkeyedUnarchiver)
特點(diǎn): 可以存儲自己定義的數(shù)據(jù)類型, 但是都是一次性的全數(shù)據(jù)操作SQLite3
特點(diǎn): 存儲一些大批量的數(shù)據(jù), 排序, 統(tǒng)計等操作Core Data
特點(diǎn): 對SQLite3的一層面向?qū)ο蟮陌b, 本質(zhì)還是要轉(zhuǎn)換成為對應(yīng)的SQL語句去執(zhí)行
在所有的存儲方式中,SQLite速度最快,效率最高.
3.什么是SQLite?
- SQLite是一款輕型的嵌入式關(guān)系數(shù)據(jù)庫
- 它占用資源非常的低,在嵌入式設(shè)備中,可能只需要幾百K的內(nèi)存就夠了
- 目前廣泛應(yīng)用于移動設(shè)備中存儲數(shù)據(jù)(Android/iOS)
- 處理數(shù)據(jù)的速度非常快,效率非常高
4.什么是數(shù)據(jù)庫?
- 數(shù)據(jù)庫(Database)是按照數(shù)據(jù)結(jié)構(gòu)來組織、存儲和管理數(shù)據(jù)的倉庫(類似于excel表格)
- 數(shù)據(jù)庫可以分為2大種類(了解)
- 關(guān)系型數(shù)據(jù)庫(主流)
- 對象型數(shù)據(jù)庫
5.關(guān)系型數(shù)據(jù)庫介紹
二.Navicat軟件的破解
1.什么是Navicat?
Navicat是數(shù)據(jù)庫管理軟件,支持大部分主流數(shù)據(jù)庫(包括SQLite)(收費(fèi),要破解)
可以通過圖形化界面的方式來管理數(shù)據(jù)庫
2.有破解版,可以去網(wǎng)上搜索下載,自己安裝,這里不做介紹
.
三.Navicat軟件的使用
.
1.創(chuàng)建SQLite數(shù)據(jù)庫
2.創(chuàng)建表
2.1 雙擊打開數(shù)據(jù)庫,在tables中點(diǎn)擊右鍵,選中NewTable
2.2 創(chuàng)建表中對應(yīng)的字段,點(diǎn)擊”+”添加字段
2.3 保存,要設(shè)置表格名稱. 名稱規(guī)范: t_名稱 如: t_student
3.設(shè)置主鍵,添加數(shù)據(jù)
.
3.1 什么是主鍵
主鍵就相當(dāng)于身份證一樣,用來區(qū)分每一條數(shù)據(jù)
3.2 設(shè)置主鍵注意點(diǎn)
3.3 添加,刪除,修改數(shù)據(jù)
3.31 直接點(diǎn)擊”+” 添加數(shù)據(jù)
注意:主鍵的值不要修改
3.32 刪除,選中一行,點(diǎn)擊”-“ 直接刪除
注意:刪除一組數(shù)據(jù)后,主鍵值就不會再被回收使用. 一個主鍵值只對應(yīng)一條數(shù)據(jù),無論數(shù)據(jù)是否存在
3.33 修改數(shù)據(jù)
雙擊想要修改的數(shù)據(jù),直接修改
四.SQLite的使用步驟
1.創(chuàng)建數(shù)據(jù)庫(一個用于存儲數(shù)據(jù)的文件)
通常后綴名為: .db 或 .sqlite
2.創(chuàng)建表用于存儲數(shù)據(jù)
- 創(chuàng)建表時需要指定該表有哪些字段
- 比如學(xué)生表有:學(xué)號/姓名/年齡/身高等
3.對表進(jìn)行增刪改查操作
- 比如添加一條學(xué)生數(shù)據(jù):型號:1/姓名:why/年齡:18/身高:1.88
五.SQL簡介
1.怎么在程序中使用SQLite?
真實(shí)使用SQLite時用代碼來操作的
2.怎么用代碼操作SQLite?
使用SQL語句來操作
3.SQL介紹 不做過多介紹,直接看下定義就行了
六.在代碼中使用DDL(數(shù)據(jù)定義語句)
1.先導(dǎo)入libsqlite3.tba框架(c語言)
2.創(chuàng)建橋接文件,配置橋接文件(不會的話,看之前筆記)
3.創(chuàng)建數(shù)據(jù)庫
// 創(chuàng)建數(shù)據(jù)庫
// 文件路徑 :
// 1.獲取數(shù)據(jù)庫的存放路徑(沙盒中)
let filePath = "/Users/xiaomage/Desktop/123.sqlite"
let cString = filePath.cStringUsingEncoding(NSUTF8StringEncoding)!
// 2.定義數(shù)據(jù)庫對象(后面還要用,定義一個屬性替代)
// var db : COpaquePointer = nil
// 3.打開/創(chuàng)建 數(shù)據(jù)庫對象
if sqlite3_open(cString, &db) == SQLITE_OK {
print("創(chuàng)建/打開數(shù)據(jù)庫成功")
} else {
print("失敗")
}
}
4.創(chuàng)建表
4.1 創(chuàng)建SQL語句
4.2 執(zhí)行語句(要對語句進(jìn)行判斷) if 語句 == SQLITE_OK
4.3 創(chuàng)建表格式
CREATE TABLE IF NOT EXISTS '表名' (
'字段名' 類型(INTEGER, REAL, TEXT, BLOB)
NOT NULL 不允許為空
PRIMARY KEY 主鍵
AUTOINCREMENT 自增長,
'字段名2' 類型,
...
)
4.4 語句說明
- CREATE TABLE:創(chuàng)建一張表
- IF NOT EXISTS:不存在則創(chuàng)建
- 't_student':表的名稱
- NOT NULL:不允許為空
- PRIMARY KEY:主鍵
- AUTOINCREMENT:自動增加
- 'id' INTEGER:有一個ID字段,類型是INTEGER
5.刪除表
5.1刪除表的格式
DROP TABLE IF EXISTS '表名';
5.2 語句說明
DROP TABLE:刪除表
IF EXISTS:存在則刪除
'表名':要刪除的表的名稱
// 1.獲取要執(zhí)行的SQL語句
let createTableSQL = "DROP TABLE IF EXISTS t_student;"
// 2.執(zhí)行語句
if sqlite3_exec(db, createTableSQL.cStringUsingEncoding(NSUTF8StringEncoding)!, nil, nil, nil) == SQLITE_OK {
print("刪除表成功")
} else {
print("刪除表失敗")
}
}
6.封裝SQL語句
6.1 創(chuàng)建/打開數(shù)據(jù)庫的代碼全部一樣,可以封裝起來
6.2 創(chuàng)建語句,執(zhí)行語句步驟都一樣,只有 語句的內(nèi)容不一樣,可以把語句當(dāng)做參數(shù),封裝起來
6.3 封裝工具類,最好把實(shí)例對象設(shè)計為單例
class SQLiteManager {
// 設(shè)計單例對象
static let shareInstance : SQLiteManager = SQLiteManager()
// 數(shù)據(jù)庫對象
var db : COpaquePointer = nil
}
// MARK:- 打開數(shù)據(jù)庫的操作
extension SQLiteManager {
func openDB(filePath : String) -> Bool {
// 1.將Swift字符串轉(zhuǎn)成C語言的字符串
let cString = filePath.cStringUsingEncoding(NSUTF8StringEncoding)!
// 3.打開/創(chuàng)建數(shù)據(jù)庫對象
return sqlite3_open(cString, &db) == SQLITE_OK
}
}
// MARK:- 執(zhí)行SQL語句
extension SQLiteManager {
func execSQL(sqlString : String) -> Bool {
// 1.將Swift字符串轉(zhuǎn)成C語言的字符串
let cSQLString = sqlString.cStringUsingEncoding(NSUTF8StringEncoding)!
// 2.執(zhí)行語句
return sqlite3_exec(db, cSQLString, nil, nil, nil) == SQLITE_OK
}
}
七.在代碼中使用DML(數(shù)據(jù)操作語句)
1.插入數(shù)據(jù)
1.1 插入數(shù)據(jù)格式
INSERT INTO 't_student' (name, age, height) VALUES ('why', 18, 1.88);
1.2 語句說明
INSERT INTO: 插入數(shù)據(jù)
't_student': 在哪一個表中插入數(shù)據(jù)
(數(shù)據(jù)的字段): 給哪些字段插入數(shù)據(jù)
-
VALUES ('why', 18, 1.88): 插入的具體值
// 1.插入數(shù)據(jù)(獲取插入語句) let insertSQL = "INSERT INTO t_student (name, age, height) VALUES ('why', 18, 1.88);" // 2.執(zhí)行語句 SQLiteManager.shareInstance.execSQL(insertSQL)
2.更新數(shù)據(jù)
1.1 更新數(shù)據(jù)格式
UPDATE 't_student' SET 字段 = '值' WHERE 條件判斷;
1.2 語句說明
UPDATE: 跟新數(shù)據(jù)
't_student': 在哪一個表中更新數(shù)據(jù)
SET 字段 = '值': 更新怎樣的數(shù)據(jù)
-
WHERE 條件判斷: 更新哪些數(shù)據(jù)
// 1.獲取更新語句 let updateSQL = "UPDATE t_student SET name = 'yz';" // 2.執(zhí)行語句 SQLiteManager.shareInstance.execSQL(updateSQL)
3.刪除數(shù)據(jù)
3.1 刪除數(shù)據(jù)格式
DELETE FROM t_student;
DELETE FROM t_student WHERE age < 50;
3.2 語句說明
DELETE FROM: 從表中刪除數(shù)據(jù)
t_student : 表名
-
可以跟條件也可以不跟:不跟表示刪除所有的數(shù)據(jù)
// 1.獲取刪除語句 let deleteSQL = "DELETE FROM t_student;" // 2.執(zhí)行語句 SQLiteManager.shareInstance.execSQL(deleteSQL)
4.真實(shí)開發(fā)如何插入數(shù)據(jù)
4.1 真實(shí)開發(fā)插入數(shù)據(jù),不可能一條一條去寫
4.2 一般來說,我們開發(fā)都是面向模型的
4.3 可以把要插入的數(shù)據(jù)包裝成模型
4.4 在模型中提供方法,快速插入數(shù)據(jù)
4.5 遍歷模型數(shù)組,利用模型中快速插入數(shù)據(jù)的方法插入數(shù)據(jù)
5.怎么把數(shù)據(jù)包裝成模型?
遍歷數(shù)據(jù),把數(shù)據(jù)的每一個字段作為模型的屬性保存起來
// 模擬從網(wǎng)絡(luò)服務(wù)器中請求到很多數(shù)據(jù)(實(shí)際中數(shù)據(jù)是網(wǎng)絡(luò)來的,這里自己寫模擬)
for _ in 0..<100 {
let name = "zs\(arc4random_uniform(100))"
let age = Int(10 + arc4random_uniform(10))
let height = 1 + Double(arc4random_uniform(10)) / 10.0
let stu = Student(name: name, age: age, height: height)
stus.append(stu)
}
模型中代碼:
class Student: NSObject {
var name : String = ""
var age : Int = 0
var height : Double = 0.0
init(name : String, age : Int, height : Double) {
self.name = name
self.age = age
self.height = height
}
}
extension Student {
func insertDB() {
// 1.插入數(shù)據(jù)(獲取插入語句)
let insertSQL = "INSERT INTO t_student (name, age, height) VALUES ('\(name)', \(age), \(height));"
// 2.執(zhí)行語句
SQLiteManager.shareInstance.execSQL(insertSQL)
}
}
控制器中快速插入
for stu in stus {
stu.insertDB()
}
6.插入數(shù)據(jù)的優(yōu)化
6.1 如果有大量數(shù)據(jù)插入,在主線程執(zhí)行,會阻塞ui
6.2 插入大量數(shù)據(jù)怎么優(yōu)化?
6.21 在子線程進(jìn)行數(shù)據(jù)插入
6.22 手動開啟事務(wù)
如果一條條數(shù)據(jù)進(jìn)行插入時,那么每插入一條數(shù)據(jù)就會開啟一次事務(wù).(開啟事務(wù)耗時)
但是如果有明確的開啟事務(wù),那么系統(tǒng)就不會在插入每條數(shù)據(jù)時,再開啟事務(wù)
dispatch_async(dispatch_get_global_queue(0, 0)) {
//獲取插入數(shù)據(jù)開始時間
let startTime = CACurrentMediaTime()
// 開啟事務(wù)
let startSQL = "BEGIN TRANSACTION;"
SQLiteManager.shareInstance.execSQL(startSQL)
for stu in self.stus {
stu.insertDB()
}
//關(guān)閉事務(wù)
let commitSQL = "COMMIT TRANSACTION;"
SQLiteManager.shareInstance.execSQL(commitSQL)
//獲取插入數(shù)據(jù)結(jié)束時間
let endTime = CACurrentMediaTime()
//獲取插入數(shù)據(jù)耗時
print(endTime - startTime)
}
}
八.在代碼中使用DQL(數(shù)據(jù)查詢語句)
.
1.查詢語句
2.查詢數(shù)據(jù)代碼實(shí)現(xiàn)步驟
2.1 獲取查詢語句
2.2 執(zhí)行查詢語句(得到的結(jié)果保存到數(shù)組中,最好是字典數(shù)組)
2.3 遍歷數(shù)組,字典轉(zhuǎn)模型
2.4 從模型中讀取數(shù)據(jù)
代碼實(shí)現(xiàn):
// 1.獲取查詢語句
let querySQL = "SELECT * FROM t_student LIMIT 30, 30;";
// 2.執(zhí)行語句 (執(zhí)行語句封裝到了一個方法里面)
guard let dictArray = SQLiteManager.shareInstance.querySQL(querySQL) else {
return
}
// 3.遍歷數(shù)組
var tempArray = [Student]()
for dict in dictArray {
// 字典轉(zhuǎn)模型
tempArray.append(Student(dict: dict))
}
for stu in tempArray {
print(stu.name, stu.age)
}
//執(zhí)行語句代碼實(shí)現(xiàn)
func querySQL(querySQL : String) -> [[String : NSObject]]? {
// 0.將Swift字符串轉(zhuǎn)成C語言字符串
let cString = querySQL.cStringUsingEncoding(NSUTF8StringEncoding)!
// 1.定義游標(biāo)(指針)
var stmt : COpaquePointer = nil
// 2.給游標(biāo)賦值
// 1> 參數(shù)一: 數(shù)據(jù)庫對象
// 2> 參數(shù)二: SQL語句
// 3> 參數(shù)三: 該SQL語句的長度 -1 --> 系統(tǒng)自動計算
// 4> 參數(shù)四: 游標(biāo)的地址
guard sqlite3_prepare_v2(db, cString, -1, &stmt, nil) == SQLITE_OK else {
return nil
}
// 3.取出所有的數(shù)據(jù)
// 3.1.定義字典數(shù)組
var dictArray = [[String : NSObject]]()
// 3.2.判斷是否有該條數(shù)據(jù)
while sqlite3_step(stmt) == SQLITE_ROW {
// 3.3.獲取字段的個數(shù)
let count = sqlite3_column_count(stmt)
// 3.4.定義字典
var dict = [String : NSObject]()
// 3.5.遍歷每一個字典
for i in 0..<count {
// 3.6.取出該列的鍵
let ckey = sqlite3_column_name(stmt, i)
guard let key = String(UTF8String : ckey) else {
continue
}
// 3.7.取出該列的值
let cvalue = UnsafePointer<Int8>(sqlite3_column_text(stmt, i))
//將c語言字符串轉(zhuǎn)成swift字符串
let value = String(UTF8String : cvalue)
// 3.8.將鍵值對放入到字典中
dict[key] = value
}
// 3.9.將字典放入到數(shù)組中
dictArray.append(dict)
}
return dictArray
}
}
九.FMDB框架的使用
.
1.FMDB框架的作用?
FMDB是用來簡化操作數(shù)據(jù)庫的框架
2.FDMB的基本使用
2.1 創(chuàng)建數(shù)據(jù)庫
private lazy var db : FMDatabase = FMDatabase(path: "/Users/xiaomage/Desktop/321.sqlite")
// 創(chuàng)建FMDatabase對象
// 打開/創(chuàng)建數(shù)據(jù)
if db.open() {
print("打開成功")
} else {
print("失敗")
}
2.2 創(chuàng)建/刪除 表 插入/更新/刪除 數(shù)據(jù)
本質(zhì)都是一樣的只有語句的內(nèi)容不一樣
將語句內(nèi)容換成對應(yīng)的操作,就能執(zhí)行該項(xiàng)操作(和SQLite語句一樣)
// 1.獲取創(chuàng)建表的語句
let createSQL = "INSERT INTO t_person (name, age, height) VALUES ('why', 18, 1.88);"
// 2.執(zhí)行語句
db.executeUpdate(createSQL, withArgumentsInArray: nil)
2.3 查詢數(shù)據(jù)
var db : FMDatabase?
func querySQL(querySQL : String) -> [[String : NSObject]]? {
// 0.判斷db是否有值 db定義為屬性
guard let db = db else {
return nil
}
// 1.執(zhí)行查詢語句 結(jié)果為集合
let results = db.executeQuery(querySQL, withArgumentsInArray: nil)
// 2.獲取數(shù)據(jù)
// 2.0.定義數(shù)據(jù)
var dictArray = [[String : NSObject]]()
// 2.1.判斷結(jié)果集中是否有內(nèi)容
while results.next() {
let count = results.columnCount()
var dict = [String : NSObject]()
for i in 0..<count {
let key = results.columnNameForIndex(i)
let value = results.stringForColumnIndex(i)
dict[key] = value
}
dictArray.append(dict)
}
return dictArray
}