添加libsqlite3.tbd General -> Linked Frameworks and Libraries -> 添加libsqlite3.tbd
添加橋接 Build Settings -> (搜索 Bridg)Objective-C Bridging Header -> 添加 項(xiàng)目名/Bridge.h
Bridge.h 添加一行如下:
#import
extension String{
/**
將當(dāng)前字符串拼接到cache目錄后面
*/
func cacheDir() -> String{
let path = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.CachesDirectory, NSSearchPathDomainMask.UserDomainMask, true).last! ?as NSString
return path.stringByAppendingPathComponent((self as NSString).lastPathComponent)
}
/**
將當(dāng)前字符串拼接到doc目錄后面
*/
func docDir() -> String
{
let path = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true).last! ?as NSString
return path.stringByAppendingPathComponent((self as NSString).lastPathComponent)
}
/**
將當(dāng)前字符串拼接到tmp目錄后面
*/
func tmpDir() -> String
{
let path = NSTemporaryDirectory() as NSString
return path.stringByAppendingPathComponent((self as NSString).lastPathComponent)
}
}
打開數(shù)據(jù)庫 :SQLiteManager.shareManager().openDB("sql.sqlite")
關(guān)閉數(shù)據(jù)庫:let bool = closeDB(db)
創(chuàng)建表:let bool = creatTable("T_Class")
查詢:let sql = "SELECT * FROM T_Class;"
let res = SQLiteManager.shareManager().execRecordSQL(sql)
刪除(更新插入修改下sql語句):
let sql = "DELETE FROM T_Class WHERE age IS 10;"
let bool = SQLiteManager.shareManager().execSQL(sql)
子線程執(zhí)行插入數(shù)據(jù)庫:
SQLiteManager.shareManager().execQueueSQL { (manager) -> () in
// 1.編寫SQL語句
let sql = "INSERT INTO T_Person" +
"(name, age)" +
"VALUES" +
"('\\(self.name!)', \\(self.age));"
// 2.執(zhí)行SQL語句
manager.execSQL(sql)
print(NSThread.currentThread())
}
事務(wù)+預(yù)編譯 提高效率:
let manager = SQLiteManager.shareManager()
// 開啟事務(wù)
manager.beginTransaction()
for i in 0..<10000
{
let sql = "INSERT INTO T_Person" +
"(name, age)" +
"VALUES" +
"(?, ?);"
manager.batchExecSQL(sql, args: "yy +\\(i)", 1 + i)
}
// 提交事務(wù)
manager.commitTransaction()
class SQLiteManager: NSObject {
private static let manager: SQLiteManager = SQLiteManager()
/// 單粒
class func shareManager() ->SQLiteManager {
return manager
}
// 數(shù)據(jù)庫對(duì)象
private var db:COpaquePointer = nil
/**
打開數(shù)據(jù)庫
:param: SQLiteName 數(shù)據(jù)庫名稱
*/
func openDB(SQLiteName: String)
{
// 0.拿到數(shù)據(jù)庫的路徑
let path = SQLiteName.docDir()
print(path)
let cPath = path.cStringUsingEncoding(NSUTF8StringEncoding)!
// 1.打開數(shù)據(jù)庫
/*
1.需要打開的數(shù)據(jù)庫文件的路徑, C語言字符串
2.打開之后的數(shù)據(jù)庫對(duì)象 (指針), 以后所有的數(shù)據(jù)庫操作, 都必須要拿到這個(gè)指針才能進(jìn)行相關(guān)操作
*/
// open方法特點(diǎn): 如果指定路徑對(duì)應(yīng)的數(shù)據(jù)庫文件已經(jīng)存在, 就會(huì)直接打開
// ? ? ? ? ? ? ?如果指定路徑對(duì)應(yīng)的數(shù)據(jù)庫文件不存在, 就會(huì)創(chuàng)建一個(gè)新的
if sqlite3_open(cPath, &db) != SQLITE_OK
{
print("打開數(shù)據(jù)庫失敗")
return
}
// 創(chuàng)建一個(gè)串行隊(duì)列
private let dbQueue = dispatch_queue_create("com.xxx.sql", DISPATCH_QUEUE_SERIAL)
/**
子線程執(zhí)行數(shù)據(jù)庫插入操作
- parameter action:閉包
*/
func execQueueSQL(action: (manager: SQLiteManager)->())
{
// 1.開啟一個(gè)子線程
dispatch_async(dbQueue) { () -> Void in
print(NSThread.currentThread())
// 2.執(zhí)行閉包
action(manager: self)
}
}
// 2.創(chuàng)建表
if creatTable("T_Class")
{
print("創(chuàng)建表成功")
}else
{
print("創(chuàng)建表失敗")
}
}
/// 自定義一個(gè)SQLITE_TRANSIENT, 覆蓋系統(tǒng)的
private let SQLITE_TRANSIENT = unsafeBitCast(-1, sqlite3_destructor_type.self)
// MARK: - 預(yù)編譯 + 事務(wù)可以提高效率
func batchExecSQL(sql:String, args: CVarArgType...) -> Bool
{
// 1.將SQL語句轉(zhuǎn)換為C語言
let cSQL = sql.cStringUsingEncoding(NSUTF8StringEncoding)!
// 2.預(yù)編譯SQL語句
var stmt: COpaquePointer = nil
if sqlite3_prepare_v2(db, cSQL, -1, &stmt, nil) != SQLITE_OK
{
print("預(yù)編譯失敗")
sqlite3_finalize(stmt)
return false
}
// 3.綁定數(shù)據(jù)
var index:Int32 = 1
for objc in args
{
if objc is Int
{
// ? ? ? ? ? ? ? ?print("通過int方法綁定數(shù)據(jù) \\(objc)")
// 第二個(gè)參數(shù)就是SQL中('?', ?)的位置, 注意: 從1開始
sqlite3_bind_int64(stmt, index, sqlite3_int64(objc as! Int))
}else if objc is Double
{
// ? ? ? ? ? ? ? ?print("通過Double方法綁定數(shù)據(jù) \\(objc)")
sqlite3_bind_double(stmt, index, objc as! Double)
}else if objc is String
{
// ? ? ? ? ? ? ? ?print("通過Text方法綁定數(shù)據(jù) \\(objc)")
let text = objc as! String
let cText = text.cStringUsingEncoding(NSUTF8StringEncoding)!
// 第三個(gè)參數(shù): 需要綁定的字符串, C語言
// 第四個(gè)參數(shù): 第三個(gè)參數(shù)的長度, 傳入-1系統(tǒng)自動(dòng)計(jì)算
// 第五個(gè)參數(shù): OC中直接傳nil, 但是Swift傳入nil會(huì)有大問題
/*
typedef void (*sqlite3_destructor_type)(void*);
#define SQLITE_STATIC ? ? ?((sqlite3_destructor_type)0)
#define SQLITE_TRANSIENT ? ((sqlite3_destructor_type)-1)
第五個(gè)參數(shù)如果傳入SQLITE_STATIC/nil, 那么系統(tǒng)不會(huì)保存需要綁定的數(shù)據(jù), 如果需要綁定的數(shù)據(jù)提前釋放了, 那么系統(tǒng)就隨便綁定一個(gè)值
第五個(gè)參數(shù)如果傳入SQLITE_TRANSIENT, 那么系統(tǒng)會(huì)對(duì)需要綁定的值進(jìn)行一次copy, 直到綁定成功之后再釋放
*/
sqlite3_bind_text(stmt, index, cText, -1, SQLITE_TRANSIENT)
}
index += 1
}
// 4.執(zhí)行SQL語句
if sqlite3_step(stmt) != SQLITE_DONE
{
print("執(zhí)行SQL語句失敗")
return false
}
// 5.重置STMT
if sqlite3_reset(stmt) != SQLITE_OK
{
print("重置失敗")
return false
}
// 6.關(guān)閉STMT
// 注意點(diǎn): 只要用到了stmt, 一定要關(guān)閉
sqlite3_finalize(stmt)
return true
}
/**
關(guān)閉數(shù)據(jù)庫
- parameter db: 數(shù)據(jù)庫
*/
func closeDB(db: COpaquePointer) -> Bool{
if sqlite3_close(db) == SQLITE_OK {
return true
}
return false
}
// MARK: - 事務(wù)相關(guān) (可以提高性能)
// 1.開啟事務(wù)
func beginTransaction()
{
execSQL("BEGIN TRANSACTION")
}
// 2.提交事務(wù)
func commitTransaction()
{
execSQL("COMMIT TRANSACTION")
}
// 3.回滾
func rollbackTransaction()
{
execSQL("ROLLBACK TRANSACTION")
}
//創(chuàng)建表
func creatTable(table: String) -> Bool
{
// 1.編寫SQL語句
let sql = "CREATE TABLE IF NOT EXISTS \\(table)( \\n" +
"id INTEGER PRIMARY KEY AUTOINCREMENT, \\n" +
"name TEXT, \\n" +
"age INTEGER \\n" +
"); \\n"
// 2.執(zhí)行SQL語句
return execSQL(sql)
}
/**
執(zhí)行除查詢以外的SQL語句
:param: sql 需要執(zhí)行的SQL語句
:returns: 是否執(zhí)行成功 true執(zhí)行成功 false執(zhí)行失敗
*/
func execSQL(sql: String) -> Bool
{
// 0.將Swift字符串轉(zhuǎn)換為C語言字符串
let cSQL = sql.cStringUsingEncoding(NSUTF8StringEncoding)!
// 在SQLite3中, 除了查詢意外(創(chuàng)建/刪除/新增/更新)都使用同一個(gè)函數(shù)
/*
1. 已經(jīng)打開的數(shù)據(jù)庫對(duì)象
2. 需要執(zhí)行的SQL語句, C語言字符串
3. 執(zhí)行SQL語句之后的回調(diào), 一般傳nil
4. 是第三個(gè)參數(shù)的第一個(gè)參數(shù), 一般傳nil
5. 錯(cuò)誤信息, 一般傳nil
*/
if sqlite3_exec(db, cSQL, nil, nil, nil) != SQLITE_OK
{
return false
}
return true
}
/**
查詢所有的數(shù)據(jù)
:returns: 查詢到的字典數(shù)組
*/
func execRecordSQL(sql: String) ->[[String: AnyObject]]
{
// 0.將Swift字符串轉(zhuǎn)換為C語言字符串
let cSQL = sql.cStringUsingEncoding(NSUTF8StringEncoding)!
// 1.準(zhǔn)備數(shù)據(jù)
// 準(zhǔn)備: 理解為預(yù)編譯SQL語句, 檢測里面是否有錯(cuò)誤等等, 它可以提供性能
/*
1.已經(jīng)開打的數(shù)據(jù)庫對(duì)象
2.需要執(zhí)行的SQL語句
3.需要執(zhí)行的SQL語句的長度, 傳入-1系統(tǒng)自動(dòng)計(jì)算
4.預(yù)編譯之后的句柄, 已經(jīng)要想取出數(shù)據(jù), 就需要這個(gè)句柄
5. 一般傳nil
*/
var stmt: COpaquePointer = nil
if sqlite3_prepare_v2(db, cSQL, -1, &stmt, nil) != SQLITE_OK
{
print("準(zhǔn)備失敗")
}
// 準(zhǔn)備成功
var records = [[String: AnyObject]]()
// 2.查詢數(shù)據(jù)
// sqlite3_step代表取出一條數(shù)據(jù), 如果取到了數(shù)據(jù)就會(huì)返回SQLITE_ROW
while sqlite3_step(stmt) == SQLITE_ROW
{
// 獲取一條記錄的數(shù)據(jù)
let record = recordWithStmt(stmt)
// 將當(dāng)前獲取到的這一條記錄添加到數(shù)組中
records.append(record)
}
// 注意點(diǎn): 只要用到了stmt, 一定要關(guān)閉
sqlite3_finalize(stmt)
// 返回查詢到的數(shù)據(jù)
return records
}
/**
獲取一條記錄的值
:param: stmt 預(yù)編譯好的SQL語句
:returns: 字典
*/
private func recordWithStmt(stmt: COpaquePointer) ->[String: AnyObject]
{
// 2.1拿到當(dāng)前這條數(shù)據(jù)所有的列
let count = sqlite3_column_count(stmt)
// ? ? ? ? ? ?print(count)
// 定義字典存儲(chǔ)查詢到的數(shù)據(jù)
var record ?= [String: AnyObject]()
for index in 0..
{
// 2.2拿到每一列的名稱
let cName = sqlite3_column_name(stmt, index)
let name = String(CString: cName, encoding: NSUTF8StringEncoding)!
// ? ? ? ? ? ? ? ?print(name)
// 2.3拿到每一列的類型 SQLITE_INTEGER
let type = sqlite3_column_type(stmt, index)
// ? ? ? ? ? ? ? ?print("name = \\(name) , type = \\(type)")
switch type
{
case SQLITE_INTEGER:
// 整形
let num = sqlite3_column_int64(stmt, index)
record[name] = Int(num)
case SQLITE_FLOAT:
// 浮點(diǎn)型
let double = sqlite3_column_double(stmt, index)
record[name] = Double(double)
case SQLITE3_TEXT:
// 文本類型
let cText = UnsafePointer(sqlite3_column_text(stmt, index))
let text = NSString(CString: cText, encoding: NSUTF8StringEncoding)!
record[name] = text
case SQLITE_NULL:
// 空類型
record[name] = NSNull()
print(record)
default:
// 二進(jìn)制類型 SQLITE_BLOB
// 一般情況下, 不會(huì)往數(shù)據(jù)庫中存儲(chǔ)二進(jìn)制數(shù)據(jù)
print("")
}
}
return record
}
}
SQLite函數(shù)總結(jié)
1.打開數(shù)據(jù)庫
int sqlite3_open(
const char *filename, ? // 數(shù)據(jù)庫的文件路徑
sqlite3 **ppDb ? ? ? ? ?// 數(shù)據(jù)庫實(shí)例
);
2.執(zhí)行任何SQL語句
int sqlite3_exec(
sqlite3*, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// 一個(gè)打開的數(shù)據(jù)庫實(shí)例
const char *sql, ? ? ? ? ? ? ? ? ? ? ? ? ? // 需要執(zhí)行的SQL語句
int (*callback)(void*,int,char**,char**), ?// SQL語句執(zhí)行完畢后的回調(diào)
void *, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// 回調(diào)函數(shù)的第1個(gè)參數(shù)
char **errmsg ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// 錯(cuò)誤信息
);
3.檢查SQL語句的合法性(查詢前的準(zhǔn)備)
int sqlite3_prepare_v2(
sqlite3 *db, ? ? ? ? ? ?// 數(shù)據(jù)庫實(shí)例
const char *zSql, ? ? ? // 需要檢查的SQL語句
int nByte, ? ? ? ? ? ? ?// SQL語句的最大字節(jié)長度
sqlite3_stmt **ppStmt, ?// sqlite3_stmt實(shí)例,用來獲得數(shù)據(jù)庫數(shù)據(jù)
const char **pzTail
);
4.查詢一行數(shù)據(jù)
int sqlite3_step(sqlite3_stmt*); // 如果查詢到一行數(shù)據(jù),就會(huì)返回SQLITE_ROW
5.利用stmt獲得某一字段的值(字段的下標(biāo)從0開始)
double sqlite3_column_double(sqlite3_stmt*, int iCol); ?// 浮點(diǎn)數(shù)據(jù)
int sqlite3_column_int(sqlite3_stmt*, int iCol); // 整型數(shù)據(jù)
sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); // 長整型數(shù)據(jù)
const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); // 二進(jìn)制文本數(shù)據(jù)
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); ?// 字符串?dāng)?shù)據(jù)
SQLite語句
/*簡單約束*/
CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER);
CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, age INTEGER NOT NULL);
CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE, age INTEGER);
CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER DEFAULT 1);
/*分頁*/
SELECT * FROM t_student ORDER BY id ASC LIMIT 30, 10;
/*排序*/
SELECT * FROM t_student WHERE score > 50 ORDER BY age DESC;
SELECT * FROM t_student WHERE score < 50 ORDER BY age ASC , score DESC;
/*計(jì)量*/
SELECT COUNT(*) FROM t_student WHERE age > 50;
/*別名*/
SELECT name as myName, age as myAge, score as myScore FROM t_student;
SELECT name myName, age myAge, score myScore FROM t_student;
SELECT s.name myName, s.age myAge, s.score myScore FROM t_student s WHERE s.age > 50;
/*查詢*/
SELECT name, age, score FROM t_student;
SELECT * FROM t_student;
/*修改指定數(shù)據(jù)*/
UPDATE t_student SET name = 'MM' WHERE age = 10;
UPDATE t_student SET name = 'WW' WHERE age is 7;
UPDATE t_student SET name = 'XXOO' WHERE age < 20;
UPDATE t_student SET name = 'NNMM' WHERE age < 50 and score > 10;
/*刪除數(shù)據(jù)*/
DELETE FROM t_student;
/*更新數(shù)據(jù)*/
UPDATE t_student SET name = 'LNJ';
/*插入數(shù)據(jù)*/
INSERT INTO t_student(age, score, name) VALUES ('28', 100, 'jonathan');
INSERT INTO t_student(name, age) VALUES ('lee', '28');
INSERT INTO t_student(score) VALUES (100);
/*插入數(shù)據(jù)*/
INSERT INTO t_student(name, age, score) VALUES ('lee', '28', 100);
/*添加主鍵*/
CREATE TABLE IF NOT EXISTS t_student (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER, score REAL);
/*添加主鍵*/
CREATE TABLE IF NOT EXISTS t_student (id INTEGER, name TEXT, age INTEGER, score REAL, PRIMARY KEY(id));
/*刪除表*/
DROP TABLE IF EXISTS t_student;
/*創(chuàng)建表*/
CREATE TABLE IF NOT EXISTS t_student(id INTEGER , name TEXT, age , score REAL);