添加libsqlite3.tbd General -> Linked Frameworks and Libraries -> 添加libsqlite3.tbd
添加桥接 Build Settings -> (搜索 Bridg)Objective-C Bridging Header -> 添加 项目名/Bridge.h
Bridge.h 添加一行如下:
#import <sqlite3.h>
extension String{
/**
将当前字符串拼接到cache目录后面
*/
func cacheDir() -> String{
let path = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.CachesDirectory, NSSearchPathDomainMask.UserDomainMask, true).last! as NSString
return path.stringByAppendingPathComponent((self as NSString).lastPathComponent)
}
/**
将当前字符串拼接到doc目录后面
*/
func docDir() -> String
{
let path = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true).last! as NSString
return path.stringByAppendingPathComponent((self as NSString).lastPathComponent)
}
/**
将当前字符串拼接到tmp目录后面
*/
func tmpDir() -> String
{
let path = NSTemporaryDirectory() as NSString
return path.stringByAppendingPathComponent((self as NSString).lastPathComponent)
}
}
打开数据库 :SQLiteManager.shareManager().openDB("sql.sqlite")
关闭数据库:let bool = closeDB(db)
创建表: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)
子线程执行插入数据库:
SQLiteManager.shareManager().execQueueSQL { (manager) -> () in
// 1.编写SQL语句
let sql = "INSERT INTO T_Person" +
"(name, age)" +
"VALUES" +
"('\(self.name!)', \(self.age));"
// 2.执行SQL语句
manager.execSQL(sql)
print(NSThread.currentThread())
}
事务+预编译 提高效率:
let manager = SQLiteManager.shareManager()
// 开启事务
manager.beginTransaction()
for i in 0..<10000
{
let sql = "INSERT INTO T_Person" +
"(name, age)" +
"VALUES" +
"(?, ?);"
manager.batchExecSQL(sql, args: "yy +\(i)", 1 + i)
}
// 提交事务
manager.commitTransaction()
class SQLiteManager: NSObject {
private static let manager: SQLiteManager = SQLiteManager()
/// 单粒
class func shareManager() ->SQLiteManager {
return manager
}
// 数据库对象
private var db:COpaquePointer = nil
/**
打开数据库
:param: SQLiteName 数据库名称
*/
func openDB(SQLiteName: String)
{
// 0.拿到数据库的路径
let path = SQLiteName.docDir()
print(path)
let cPath = path.cStringUsingEncoding(NSUTF8StringEncoding)!
// 1.打开数据库
/*
1.需要打开的数据库文件的路径, C语言字符串
2.打开之后的数据库对象 (指针), 以后所有的数据库操作, 都必须要拿到这个指针才能进行相关操作
*/
// open方法特点: 如果指定路径对应的数据库文件已经存在, 就会直接打开
// 如果指定路径对应的数据库文件不存在, 就会创建一个新的
if sqlite3_open(cPath, &db) != SQLITE_OK
{
print("打开数据库失败")
return
}
// 创建一个串行队列
private let dbQueue = dispatch_queue_create("com.xxx.sql", DISPATCH_QUEUE_SERIAL)
/**
子线程执行数据库插入操作
- parameter action:闭包
*/
func execQueueSQL(action: (manager: SQLiteManager)->())
{
// 1.开启一个子线程
dispatch_async(dbQueue) { () -> Void in
print(NSThread.currentThread())
// 2.执行闭包
action(manager: self)
}
}
// 2.创建表
if creatTable("T_Class")
{
print("创建表成功")
}else
{
print("创建表失败")
}
}
/// 自定义一个SQLITE_TRANSIENT, 覆盖系统的
private let SQLITE_TRANSIENT = unsafeBitCast(-1, sqlite3_destructor_type.self)
// MARK: - 预编译 + 事务可以提高效率
func batchExecSQL(sql:String, args: CVarArgType...) -> Bool
{
// 1.将SQL语句转换为C语言
let cSQL = sql.cStringUsingEncoding(NSUTF8StringEncoding)!
// 2.预编译SQL语句
var stmt: COpaquePointer = nil
if sqlite3_prepare_v2(db, cSQL, -1, &stmt, nil) != SQLITE_OK
{
print("预编译失败")
sqlite3_finalize(stmt)
return false
}
// 3.绑定数据
var index:Int32 = 1
for objc in args
{
if objc is Int
{
// print("通过int方法绑定数据 \(objc)")
// 第二个参数就是SQL中('?', ?)的位置, 注意: 从1开始
sqlite3_bind_int64(stmt, index, sqlite3_int64(objc as! Int))
}else if objc is Double
{
// print("通过Double方法绑定数据 \(objc)")
sqlite3_bind_double(stmt, index, objc as! Double)
}else if objc is String
{
// print("通过Text方法绑定数据 \(objc)")
let text = objc as! String
let cText = text.cStringUsingEncoding(NSUTF8StringEncoding)!
// 第三个参数: 需要绑定的字符串, C语言
// 第四个参数: 第三个参数的长度, 传入-1系统自动计算
// 第五个参数: OC中直接传nil, 但是Swift传入nil会有大问题
/*
typedef void (*sqlite3_destructor_type)(void*);
#define SQLITE_STATIC ((sqlite3_destructor_type)0)
#define SQLITE_TRANSIENT ((sqlite3_destructor_type)-1)
第五个参数如果传入SQLITE_STATIC/nil, 那么系统不会保存需要绑定的数据, 如果需要绑定的数据提前释放了, 那么系统就随便绑定一个值
第五个参数如果传入SQLITE_TRANSIENT, 那么系统会对需要绑定的值进行一次copy, 直到绑定成功之后再释放
*/
sqlite3_bind_text(stmt, index, cText, -1, SQLITE_TRANSIENT)
}
index += 1
}
// 4.执行SQL语句
if sqlite3_step(stmt) != SQLITE_DONE
{
print("执行SQL语句失败")
return false
}
// 5.重置STMT
if sqlite3_reset(stmt) != SQLITE_OK
{
print("重置失败")
return false
}
// 6.关闭STMT
// 注意点: 只要用到了stmt, 一定要关闭
sqlite3_finalize(stmt)
return true
}
/**
关闭数据库
- parameter db: 数据库
*/
func closeDB(db: COpaquePointer) -> Bool{
if sqlite3_close(db) == SQLITE_OK {
return true
}
return false
}
// MARK: - 事务相关 (可以提高性能)
// 1.开启事务
func beginTransaction()
{
execSQL("BEGIN TRANSACTION")
}
// 2.提交事务
func commitTransaction()
{
execSQL("COMMIT TRANSACTION")
}
// 3.回滚
func rollbackTransaction()
{
execSQL("ROLLBACK TRANSACTION")
}
//创建表
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.执行SQL语句
return execSQL(sql)
}
/**
执行除查询以外的SQL语句
:param: sql 需要执行的SQL语句
:returns: 是否执行成功 true执行成功 false执行失败
*/
func execSQL(sql: String) -> Bool
{
// 0.将Swift字符串转换为C语言字符串
let cSQL = sql.cStringUsingEncoding(NSUTF8StringEncoding)!
// 在SQLite3中, 除了查询意外(创建/删除/新增/更新)都使用同一个函数
/*
1. 已经打开的数据库对象
2. 需要执行的SQL语句, C语言字符串
3. 执行SQL语句之后的回调, 一般传nil
4. 是第三个参数的第一个参数, 一般传nil
5. 错误信息, 一般传nil
*/
if sqlite3_exec(db, cSQL, nil, nil, nil) != SQLITE_OK
{
return false
}
return true
}
/**
查询所有的数据
:returns: 查询到的字典数组
*/
func execRecordSQL(sql: String) ->[[String: AnyObject]]
{
// 0.将Swift字符串转换为C语言字符串
let cSQL = sql.cStringUsingEncoding(NSUTF8StringEncoding)!
// 1.准备数据
// 准备: 理解为预编译SQL语句, 检测里面是否有错误等等, 它可以提供性能
/*
1.已经开打的数据库对象
2.需要执行的SQL语句
3.需要执行的SQL语句的长度, 传入-1系统自动计算
4.预编译之后的句柄, 已经要想取出数据, 就需要这个句柄
5. 一般传nil
*/
var stmt: COpaquePointer = nil
if sqlite3_prepare_v2(db, cSQL, -1, &stmt, nil) != SQLITE_OK
{
print("准备失败")
}
// 准备成功
var records = [[String: AnyObject]]()
// 2.查询数据
// sqlite3_step代表取出一条数据, 如果取到了数据就会返回SQLITE_ROW
while sqlite3_step(stmt) == SQLITE_ROW
{
// 获取一条记录的数据
let record = recordWithStmt(stmt)
// 将当前获取到的这一条记录添加到数组中
records.append(record)
}
// 注意点: 只要用到了stmt, 一定要关闭
sqlite3_finalize(stmt)
// 返回查询到的数据
return records
}
/**
获取一条记录的值
:param: stmt 预编译好的SQL语句
:returns: 字典
*/
private func recordWithStmt(stmt: COpaquePointer) ->[String: AnyObject]
{
// 2.1拿到当前这条数据所有的列
let count = sqlite3_column_count(stmt)
// print(count)
// 定义字典存储查询到的数据
var record = [String: AnyObject]()
for index in 0..<count
{
// 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:
// 浮点型
let double = sqlite3_column_double(stmt, index)
record[name] = Double(double)
case SQLITE3_TEXT:
// 文本类型
let cText = UnsafePointer<Int8>(sqlite3_column_text(stmt, index))
let text = NSString(CString: cText, encoding: NSUTF8StringEncoding)!
record[name] = text
case SQLITE_NULL:
// 空类型
record[name] = NSNull()
print(record)
default:
// 二进制类型 SQLITE_BLOB
// 一般情况下, 不会往数据库中存储二进制数据
print("")
}
}
return record
}
}
-
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语句
/*简单约束*/ 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; /*计量*/ 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; /*修改指定数据*/ 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; /*删除数据*/ DELETE FROM t_student; /*更新数据*/ UPDATE t_student SET name = 'LNJ'; /*插入数据*/ 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); /*插入数据*/ 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; /*创建表*/ CREATE TABLE IF NOT EXISTS t_student(id INTEGER , name TEXT, age , score REAL);