开发中,使用到数据库一般会使用FMDB这个第三方库,来简化使用。FMDB是iOS平台的SQLite数据库框架,它以OC的方式封装了SQLite的C语言API。使用起来更加面向对象,省去了很多麻烦、冗余的C语言代码,对比苹果自带的Core Data框架,更加轻量级和灵活,提供了多线程安全的数据库操作方法,有效地防止数据混乱。
1. FMDB的核心类
FMDB有三个主要的类:
FMDatabase:一个FMDatabase对象就代表一个单独的SQLite数据库,用来执行SQL语句。
FMResultSet:使用FMResultSet执行查询后的结果集。
FMDatabaseQueue:用于在多线程中执行多个查询或更新,它是线程安全的。
2. FMDB的方法介绍
2.1 更新update
在FMDB中,除查询以外的所有操作,都称为“更新”。create、drop、insert、update、delete等
使用executeUpdate:方法执行更新
- (BOOL)executeUpdate:(NSString*)sql, ...
- (BOOL)executeUpdateWithFormat:(NSString*)format, ...
- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments
2.2 查询query
查询方法
- (FMResultSet *)executeQuery:(NSString*)sql, ...
- (FMResultSet *)executeQueryWithFormat:(NSString*)format, ...
- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments
示例
// 查询数据
FMResultSet *rs = [db executeQuery:@"SELECT * FROM t_student"];
// 遍历结果集
while ([rs next]) {
NSString *name = [rs stringForColumn:@"name"];
int age = [rs intForColumn:@"age"];
double score = [rs doubleForColumn:@"score"];
}
3. FMDB的使用
和c语言框架一样,FMDB通过指定SQLite数据库文件路径来创建FMDatabase对象,但FMDB更加容易理解,使用起来更容易,使用之前一样需要导入sqlite3.dylib。
3.1 文件路径有三种情况
(1)具体文件路径
如果不存在会自动创建
(2)空字符串@""
会在临时目录创建一个空的数据库
当FMDatabase连接关闭时,数据库文件也被删除
(3)nil
会创建一个内存中临时数据库,当FMDatabase连接关闭 时,数据库会被销毁
当FMDatabase连接关闭时,数据库文件也被删除
3.2 打开数据库方法如下
var db: FMDatabase?
/**
* 打开数据库
*/
func openDB(DBName: String)
{
// 1.根据传入的数据库名称拼接数据库路径
let path = DBName.docDir()
// 2.创建数据库对象
db = FMDatabase(path: path)
// 3.打开数据库
// open方法特点: 如果指定路径对应的数据库文件已经存在, 就会直接打开
// 如果指定路径对应的数据库文件不存在, 就会创建一个新的
if !db!.open()
{
print("打开数据库失败")
return
}
// 4.创建表
creatTable()
}
private func creatTable()
{
// 1.编写SQL语句
let sql = "CREATE TABLE IF NOT EXISTS T_Person( \n" +
"id INTEGER PRIMARY KEY AUTOINCREMENT, \n" +
"name TEXT, \n" +
"age INTEGER \n" +
"); \n"
// 2.执行SQL语句
// 注意点: 在FMDB中除了查询意外, 都称之为更新
if db!.executeUpdate(sql, withArgumentsInArray: nil)
{
print("创建表成功")
}else
{
print("创建表失败")
}
}
4. FMDatabaseQueue的使用
如果应用中使用了多线程操作数据库,那么就需要使用FMDatabaseQueue来保证线程安全了。 应用中不可在多个线程中共同使用一个FMDatabase对象操作数据库,这样会引起数据库数据混乱。 为了多线程操作数据库安全,FMDB使用了FMDatabaseQueue,使用FMDatabaseQueue很简单,首先用一个数据库文件地址来初使化FMDatabaseQueue,然后就可以将一个闭包(block)传入inDatabase方法中。 在闭包中操作数据库,而不直接参与FMDatabase的管理。
4.1 创建打开数据库
var dbQueue: FMDatabaseQueue?
/**
* 打开数据库
*/
func openDB(DBName: String)
{
// 1.根据传入的数据库名称拼接数据库路径
let path = DBName.docDir()
// 2.创建数据库对象
// 注意: 如果是使用FMDatabaseQueue创建数据库对象, 那么就不用打开数据库
dbQueue = FMDatabaseQueue(path: path)
// 4.创建表
creatTable()
}
private func creatTable()
{
// 1.编写SQL语句
let sql = "CREATE TABLE IF NOT EXISTS T_Person( \n" +
"id INTEGER PRIMARY KEY AUTOINCREMENT, \n" +
"name TEXT, \n" +
"age INTEGER \n" +
"); \n"
// 2.执行SQL语句
dbQueue!.inDatabase { (db) -> Void in
db.executeUpdate(sql, withArgumentsInArray: nil)
}
}
4.2 插入记录
/**
插入一条记录
*/
func insertPerson()
{
assert(name != nil, "必须要给name赋值")
// 1.编写SQL语句
let sql = "INSERT INTO T_Person" +
"(name, age)" +
"VALUES" +
"('\(name)', \(age));"
// 2.执行SQL语句
// 只要在inTransaction闭包中执行的语句都是已经开启事务的
/*
第一个参数: 已经打开的数据库对象
第二个参数: 用于设置是否需要回滚数据
*/
SQLiteManager.shareManager().dbQueue?.inTransaction({ (db, rollback) -> Void in
if !db.executeUpdate(sql, withArgumentsInArray: nil)
{
// 如果插入数据失败, 就回滚
// OC中的写法 : *rollback = YES;
// Swift中的写法: rollback.memory = true
rollback.memory = true
}
})
}
4.3 查询
// MARK: - 执行数据源CRUD的操作
class func loadPersons(finished: ([Person])->())
{
let sql = "SELECT * FROM T_Person;"
SQLiteManager.shareManager().dbQueue?.inDatabase({ (db) -> Void in
let res = db.executeQuery(sql, withArgumentsInArray: nil)
// next取出一行数据
var models = [Person]()
while res.next()
{
let p = Person()
let num = res.intForColumn("id")
let name = res.stringForColumn("name")
let age = res.intForColumn("age")
print("num = \(num), name = \(name), age = \(age)")
p.id = Int(num)
p.name = name
p.age = Int(age)
models.append(p)
}
finished(models)
})
}