本人有若干成套学习视频, 可试看! 可试看! 可试看, 重要的事情说三遍 包含Java
, 数据结构与算法
, iOS
, 安卓
, python
, flutter
等等, 如有需要, 联系微信tsaievan
.
SQLite = SQL + Lite(light)
SQL = Structured Query Language (结构化查询语言)
SQLite 是一款轻型的数据库, 具有以下特点:
- 嵌入式的
- 占用资源少, 运行速度快
- Mac 已经内置了 SQLite
关系型数据库的特点
- 一个字段(field/col)存储一个值,类似于存储的一个属性
- 一行(row)存储一条记录,类似于一个对象
- 一个表(table)存储一系列数据,类似于一个对象数组
- 多个表之间存在一定的关系,类似于对象之间的关系
相关术语
-
字段(field/col),一个字段存储一个值,可以存储 INTEGER ,REAL ,TEXT ,BLOB,NULL 等五种类型的数据
- SQLite 存储在本质上并不区分数据类型
主键(primary key)
- 自动增长,程序员不需要关心
- 外键(foreign key)
- 通过外键对应起和其他"表(table)"的关系
开发数据库的步骤(关键)
- 建立数据库 ->有存储数据的文件
- 创建表->每一张数据表存储一类数据
- 利用 SQL 语句对其进行增删查改,并在 UI 中显示
移动应用中使用数据库的好处
实际上,随着 4G 网络的普及以及数据的更新数据加快,这一优势正在慢慢削弱
- 将网络数据存储在本地,不用每次网络下载,节省用户流量
- 对本地数据进行查询
使用第三方框架 FMDB 来操作 SQLite 数据库的 Demo
iOS原生的操作数据库的方法十分繁琐, 所以一般使用第三方框架来操作SQLite 数据库.
总体思路导图
在使用的过程中,需要用到一些常用的 SQL 语句,这些语句对于一些非专业的开发人员来说,不需要去记忆,我们只需要安装 navicat 这个软件,然后会自动生成一些常用的 SQL 命令,我们将其 copy 下来供日后使用
下文即是 demo 的主要步骤
- 在 pod 中导入 FMDB
- 在target 中添加FMDatabaseAdditionsVariadic和FMDatabaseVariadic两个 swift 文件
先介绍一下 FMDBDatabase 类
我们首先要创建一个中间管理层对 FMDBDatabase 类进行一个封装
这个中间管理层就叫做 FMDBManager
FMDBManager中的代码
import UIKit
/* 导入 FMDB 框架 (不同的命名空间)*/
import FMDB
class FMDBManager: NSObject {
//--------- 首先创建一个单例(管理工具类) ---------
static let sharerdManager = FMDBManager()
var db: FMDatabase?
//--------- 创建数据库 ---------
func openDB() {
/* 首先给出一个路径 */
/* NSSearchPathForDirectoriesInDomains返回的是一个数组,所以要取出最后一个元素才能获得路径,否则无法拼接出正确的地址,那么在获取路径的时候就获取不到,造成无法创建数据库文件 */
let path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).last!
/* 打印出存储路径,供查询使用 */
print(path)
/* 给数据库起一个名字 */
let databaseName = "testSqlite.sqlite"
/* 将数库的名字拼接在路径后面 */
let databasePath = "\(path)/\(databaseName)"
//--------- 初始化 db ---------
db = FMDatabase(path: databasePath)
if db!.open() {
print("数据连接成功")
//--------- 创建一个表 ---------
creatTable()
}else{
print("数据连接失败")
}
}
//--------- 关于FMDBDatabase的使用 ---------
/* 1. 创建,增删改 均使用 executeUpdate*/
/* 2. 查询使用 executeQuery方法*/
func creatTable() {
//--------- 执行 sql 语句(不需要记忆)创建一个表格 ---------
let sql = "CREATE TABLE IF NOT EXISTS t_emotion ('id' integer NOT NULL,'png' text NOT NULL,'text' text NOT NULL,PRIMARY KEY('id'))"
// func executeUpdate(sql:String, _ values: AnyObject...) throws
/* 当看到方法中出现 throws 时,必须做异常处理,否则报错 */
try! db?.executeUpdate(sql, [])
}
}
- 我们将对数据库进行增,删,改的操作都交给 模型来处理
假定一个应用场景是将所有的表情(例如emoji表情)都存储在数据库中,那么我就可以将每一个表情都看作是一个模型,将模型存储在数据库中,先创建一个模型类 EmotionModel 类
EmotionModel 类中的代码:
import UIKit
class EmotionModel: NSObject {
/* 图片 */
var png:String?
/* 名称 */
var text:String?
/* kvc 构造函数 */
init(dict:[String:AnyObject]) {
super.init()
setValuesForKeysWithDictionary(dict)
}
/* 异常处理 */
override func setValue(value: AnyObject?, forUndefinedKey key: String) {}
}
// MARK:- 对数据库进行相关的操作
extension EmotionModel {
/* 添加数据 */
func insert () {
/* 执行添加数据的 sql 语句 */
let sql = "INSERT INTO 't_emotion' ('png', 'text') values ('\(self.png!)', '\(self.text!)')"
try! FMDBManager.sharerdManager.db?.executeUpdate(sql, [])
}
}
- 这样, 在控制器中,假如我要添加模型 就只需要将 plist 文件中,或者网络加载出的 JSON 数据,字典转模型,再调用模型的对象方法,将模型对象存储到数据库中即可,控制器中的代码如下:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// insertData()
queryData()
}
}
// MARK:- 操作数据,更新 UI
//--------- 在控制器中我们只管理 UI 的相关操作,从数据库中获取数据我们交给模型来操作 ---------
/* 比如我们想在数据库的表中添加数据,就直接交给模型来做 */
extension ViewController {
/* 先创建100个模型,放到数据库的表中 */
func insertData() {
for i in 0..<100 {
let dict = ["png":"\(i).png", "text":"测试\(i)"]
let emotionModel = EmotionModel(dict: dict)
emotionModel.insert()
}
}
}
- 如果我需要查询数据,就需要使用到另外一个方法: executeQuery,这个方法是有返回值的,返回值是一个 FMResultSet 对象,假设我们现在有一个应用场景是将数据库中的所有数据打印出来,那么我们就在模型类中提供一个类方法,供外界调用
EmotionModel 类中的补充代码
class func query ()->[[String : AnyObject]] {
/* 该 sql 语句是选中表中的某一个 row */
let sql = "SELECT * FROM t_emotion"
/* executeQuery方法的返回值是一个FMResultSet类型的数据 */
/* 创建一个可变的数组,数组里面的元素是字典 */
var dataArray : [[String : AnyObject]] = []
if let result = try! FMDBManager.sharerdManager.db?.executeQuery(sql, []) {
while result.next() {
let png = result.stringForColumn("png")
let text = result.stringForColumn("text")
let dict = ["png":png, "text":text]
dataArray.append(dict)
}
}
return dataArray
}
- 此时我们在控制器中调用的时候就可以直接调用模型类方法的 API,代码如下:
func queryData () {
let dataArray = EmotionModel.query()
print(dataArray)
}
再介绍一下 FMDBDatabaseQueue 类
考虑到线程安全问题, 推荐使用 FMDBDatabaseQueue类,其实FMDBDatabaseQueue和 FMDBDatabase 类基本一样,只是多了一个闭包,将我们要执行的数据库操作放到闭包里去实现
同样需要创建一个中间层的管理类,叫做 FMDBQueueManager 类
代码如下
import UIKit
import FMDB
class FMDBQueueManager: NSObject {
//--------- 同样 ,我们先创建一个管理类的单例 ---------
static let sharedQueueManager = FMDBQueueManager()
//--------- 我们为这个管理类设置一个属性,是 FMDBDatabaseQueue 类 ---------
var dbQueue : FMDatabaseQueue?
//--------- 创建并打开数据库的方法 ---------
func openDB () {
/* 首先给出一个路径 */
let path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).last!
/* 将路径打印出来供调试使用 */
print(path)
/* 给数据库起一个名字 */
let databaseName = "sqliteTestTwo.sqlite"
/* 拼接路径 */
let databasePath = "\(path)/\(databaseName)"
/* 初始化 dbQueue */
dbQueue = FMDatabaseQueue(path: databasePath)
/* 创建一个表 */
creatTable ()
}
}
extension FMDBQueueManager {
func creatTable () {
/* 给出一个创建表的 sql 语句 */
let sql = "CREATE TABLE IF NOT EXISTS t_emotion ('id' integer NOT NULL,'png' text NOT NULL,'text' text NOT NULL,PRIMARY KEY('id'))"
/* 将执行 sql 语句的操作放到闭包中去执行 */
dbQueue?.inDatabase({ (FMDatabase) in
/* 一定要注意,这里是使用 executeUpdate,而不是 executeQuery */
try! FMDatabase.executeUpdate(sql, [])
})
}
}
- 那么在模型类中的添加数据的代码也将改变,EmotionModel 中的代码如下
/* 添加数据 */
func insert () {
/* 执行添加数据的 sql 语句 */
let sql = "INSERT INTO 't_emotion' ('png', 'text') values ('\(self.png!)', '\(self.text!)')"
FMDBQueueManager.sharedQueueManager.dbQueue?.inDatabase({ (FMDatabase) in
try! FMDatabase.executeUpdate(sql, [])
})
}
- 控制器中的代码完全不需要变化
- 在模型类中,查询数据库的代码也需要作出改变,代码如下:
class func query ()->[[String : AnyObject]] {
/* 该 sql 语句是选中表中的某一个 row */
let sql = "SELECT * FROM t_emotion"
/* executeQuery方法的返回值是一个FMResultSet类型的数据 */
/* 创建一个可变的数组,数组里面的元素是字典 */
var dataArray : [[String : AnyObject]] = []
FMDBQueueManager.sharedQueueManager.dbQueue?.inDatabase({ (FMDatabase) in
if let result = try! FMDatabase?.executeQuery(sql, []) {
while result.next() {
let png = result.stringForColumn("png")
let text = result.stringForColumn("text")
let dict = ["png":png, "text":text]
dataArray.append(dict)
}
}
})
return dataArray
}
运行结果如下