数据库操作之FMDB

iOS中使用的是sqlite3数据库,操作数据库的时候首先需要会数据库操作语句—sql语句,在代码中操作数据库时,可以先利用其它数据库软件编写sql语句并验证是否正确(相关软件:Navicat Premium)

基本知识

数据库操作之FMDB_第1张图片
数据库操作之FMDB_第2张图片
数据库操作之FMDB_第3张图片
数据库操作之FMDB_第4张图片
数据库操作之FMDB_第5张图片
数据库操作之FMDB_第6张图片
数据库操作之FMDB_第7张图片
数据库操作之FMDB_第8张图片
数据库操作之FMDB_第9张图片
数据库操作之FMDB_第10张图片
数据库操作之FMDB_第11张图片
数据库操作之FMDB_第12张图片
数据库操作之FMDB_第13张图片
数据库操作之FMDB_第14张图片
数据库操作之FMDB_第15张图片
数据库操作之FMDB_第16张图片
数据库操作之FMDB_第17张图片
数据库操作之FMDB_第18张图片
数据库操作之FMDB_第19张图片
数据库操作之FMDB_第20张图片
数据库操作之FMDB_第21张图片
数据库操作之FMDB_第22张图片
数据库操作之FMDB_第23张图片
数据库操作之FMDB_第24张图片
数据库操作之FMDB_第25张图片
数据库操作之FMDB_第26张图片

数据库操作sql基本语句

-- SQL语法
-- 单行注释
/*多行注释*/
-- 不区分大小写
-- 每条语句后面加;
-- 字符串以''括起来
-- 字段类型:text -> 字符串类型 integer -> 整型 real -> 浮点型

-- DDL语句
-- 1.创建表
-- 格式1:CREATE TABLE 表名(字段名1 字段1类型,字段名2 字段2类型,...)
-- CREATE TABLE t_Student('name' text,'age' integer,'score' real);
-- 格式2(常用):CREATE TABLE IF NOT EXISTS 表名(字段名1 字段1类型,字段名2 字段2类型,...)
-- CREATE TABLE IF NOT EXISTS t_Student(name text,age integer,score real);
-- 完整的创建表的示例:(必须设置主键)
CREATE TABLE
IF NOT EXISTS t_Student (
    id integer PRIMARY KEY AUTOINCREMENT,
    name text NOT NULL,
    age integer DEFAULT 18,
    studyId integer UNIQUE,
    score real
);

-- 2.删除表
-- 格式1:DROP TABLE 表名
-- DROP TABLE t_Student;
-- 格式2(常用):DROP TABLE IF EXISTS 表名
-- DROP TABLE IF EXISTS t_Student;

-- DML语句
-- 1.插入数据:INSERT INTO 表名(字段名1,字段名2,...) VALUES(字段1的值,字段2的值,...)
-- INSERT INTO t_Student(name,age,score) VALUES('小明',20,90);
-- INSERT INTO t_Student(name,age,score) VALUES('小红',22,89);
-- INSERT INTO t_Student(name,age,score) VALUES('小芳',23,96);
INSERT INTO t_Student(name,age,score,studyId) VALUES('小明',10,98,160501)

-- 2.修改数据
-- 格式:UPDATE 表名 SET 字段名1=字段1的新值,字段名2=字段2的新值,...
-- UPDATE t_Student SET 'age'=18; --注意:这样写所有数据的age都会变成18
-- 将表中'小明'的年龄改成18
-- UPDATE t_Student SET age = 18 WHERE name = '小明';

-- 3.删除数据
-- 格式:DELETE FROM 表名
-- DELETE FROM t_Student; --注意:这样是删除表中所有的数据
-- 删除成绩小于90的学生
-- DELETE FROM t_Student WHERE score < 90;

-- DQL语句
-- 1.查询数据
-- 格式1:SELECT 字段名1,字段名2,... FROM 表名(字段名不能用''括起来)
-- SELECT name,score FROM t_Student; -- 查询指定字段的数据
-- 格式2:SELECT * FROM 表名 
-- SELECT * FROM t_Student; -- 查询表中所有的数据
-- 获取表中年龄大于20且成绩小于90的学生的信息
-- SELECT * FROM t_Student WHERE age > 20 AND score < 90;

-- 2.获取表中的数据的个数
-- 格式1:SELECT count(*) FROM 表名
-- SELECT count(*) FROM t_Student;
-- 查询成绩小于90的学生的数量
-- SELECT count(*) FROM t_Student WHERE score < 90;

-- 3.对查询结果进行排序
-- 格式:SELECT * FROM 表名 ORDER BY 字段名 升序/降序
-- SELECT * FROM t_Student ORDER BY score; (默认asc升序)
-- SELECT * FROM t_Student ORDER BY score DESC;(降序)

-- 4.限制查询的结果的数量
-- 格式:SELECT * FROM 表名 LIMIT 数值1,数值2(跳过数值1条数据[从第0条开始数],每次查询数值2条数据)
-- SELECT * FROM t_Student LIMIT 1,2;

Swift利用OC第三方库FMDB数据库操作

在OC中可以直接使用系统的sqlite3库文件进行数据库操作,在swift中直接操作sqlite3需要从c语言层进行封装,比较复杂,所以在swift中使用FMDB(实质是OC的第三方库)来操作数据库,FMDB是基于sqlite3进行封装,所以在使用的时候需要在工程中导入sqlite3库文件
  Swift操作数据库需要用到OC的第三方库FMDB(如何使用第三方库请看下方的跳转),在使用sqlite3时要先调用sqlite3,然后在桥接文件导入sqlite3.h

数据库操作之FMDB_第27张图片
步骤1调用sqlite3
数据库操作之FMDB_第28张图片
步骤2桥接文件导入

如何使用第三方库
传送门:http://www.jianshu.com/p/734f7b1280f3

数据库操作步骤:
1.创建数据库对象并打开数据库
2.创建表
3.数据的增删改查

注意:
数据库的所有操作都必须在数据库打开的前提下进行

import UIKit

//在OC中可以直接使用系统的sqlite3库文件进行数据库操作,在swift中直接操作sqlite3需要从c语言层进行封装,所以在swift中使用FMDB(实质是OC的第三方库)来操作数据库
//FMDB是基于sqlite3进行封装,所以在使用的时候需要在工程中导入sqlite3库文件

//数据库操作步骤:
//注意:数据库的所有操作都必须在数据库打开的前提下进行
//1.创建数据库对象并打开数据库
//2.创建表
//3.数据的增删改查

class ViewController: UIViewController {

    //MARK: - 属性
    //1.数据库
    lazy var db: FMDatabase = {
        //创建数据库对象(实质是将本地数据库文件和数据库对象关联)
        //参数:数据库文件的路径(实际开发中是沙盒下的路径)后缀是.sqlite或者.db
        //如果参数关联的数据库文件存在就直接关联,不存在就自动创建
        let tdb = FMDatabase(path: "/Users/IOS1605/Desktop/user.sqlite")//按自己的电脑修改
        //MARK: - 打开数据库
        //返回值:bool
        let ret = tdb.open()
        if ret{
            print("数据库打开成功")
        }
        else{
            print("数据库打开失败")
        }
        return tdb
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //self.creatTable()
        
        //插入单条数据
        //self.insertData()
        
        //插入多条数据
//        for item in 0...100{
//            let name = "name\(item)"
//            let age = arc4random() % 15 + 15
//            let sex = arc4random() % 2 == 0 ? "男" : "女"
//            self.insertData(name, age: Int(age), sex: sex)
//        }
        
        //更新数据
        //self.updateData()
        
        //删除数据
        //self.deleteData()
        
        //获取数据
        self.getData()
    }
}

//MARK: - 数据库操作
extension ViewController{
    
    //MARK: - 创建表
    func creatTable(){
        //1.创建新建表的sql语句
        let sqlStr = "CREATE TABLE IF NOT EXISTS t_Person (id integer PRIMARY KEY AUTOINCREMENT,name text NOT NULL,age integer DEFAULT 20,sex text DEFAULT '女');"
        
        //2.执行sql语句
        //参数1:需要执行的sql语句
        //参数2:sql语句中的占位符对应的值(下面代码有讲解)
        //返回值:bool
        let ret = self.db.executeUpdate(sqlStr, withArgumentsInArray: [])
        
        //3.判断执行结果
        if ret {
            print("sql语句执行成功")
        }
        else{
            print("sql语句执行失败")
        }
    }
    
    //MARK: - 插入单条数据
    func insertData(){
        //1.创建sql语句
        let sqlStr = "INSERT INTO t_Person(name,sex,age) VALUES('小明','男',22);"
        
        //2.执行sql语句
        let ret = self.db.executeUpdate(sqlStr, withArgumentsInArray: [])
        
        //3.判断执行结果
        if ret {
            print("数据插入成功")
        }
        else{
            print("数据插入失败")
        }
    }
    
    //MARK: - 插入多条数据
    func insertData(name:String,age:Int,sex:String){
        
        //"?"是sql语句中的占位符,sql语句中不确定的值可以用"?"来代替,在执行sql语句的时候再给这个问号对应的值赋值
        let sqlStr = "INSERT INTO t_Person(name,sex,age) VALUES(?,?,?);"
        
        //2.执行sql语句
        //参数1:需要执行的sql语句
        //参数2:sql语句中的占位符对应的值
        //返回值:bool
        let ret = self.db.executeUpdate(sqlStr, withArgumentsInArray: [name,sex,age])
        
        //3.判断执行结果
        if ret {
            print("数据插入成功")
        }
        else{
            print("数据插入失败")
        }
    }
    
    //MARK: - 更新数据
    func updateData(){
        //1.创建sql语句
        let sqlStr = "UPDATE t_Person SET age = 18 WHERE age < 18;"
        
        //2.执行sql语句
        let ret = self.db.executeUpdate(sqlStr, withArgumentsInArray: [])
        
        //3.判断执行结果
        if ret {
            print("数据更新成功")
        }
        else{
            print("数据更新失败")
        }
    }
    
    //MARK: - 删除数据
    func deleteData(){
        //1.创建sql语句
        let sqlStr = "DELETE FROM t_Person WHERE age < 21 AND sex = '男';"
        
        //2.执行sql语句
        let ret = self.db.executeUpdate(sqlStr, withArgumentsInArray: [])
        
        //3.判断执行结果
        if ret {
            print("数据删除成功")
        }
        else{
            print("数据删除失败")
        }
    }
    
    //数据查询
    func getData(){
        //1.创建sql语句
        let sqlStr = "SELECT * FROM t_Person;"
        
        //2.执行sql语句
        //参数1:需要执行的sql语句
        //参数2:sql语句中的占位符对应的值
        //返回值:查询结果的集合
        let dataSet = self.db.executeQuery(sqlStr, withArgumentsInArray: [])
        
        //3.获取结果集合中的数据
        while dataSet.next(){
            //获取每个结果的内容
            //字符串和二进制通过object方式获取
            //参数:字段名字
            let name = dataSet.objectForColumnName("name")
            let sex = dataSet.objectForColumnName("sex")
            
            //获取整型数据使用int开头的方法(获取浮点型数据使用double开头的方法)
            let age = dataSet.intForColumn("age")
            
            print(name,age,sex)
        }
    }
}

将网络请求与数据库结合使用

本例子实现的效果是将网络请求的数据通过数据库缓存到本地,StoryBoard启动页面已经改成MyViewController

数据库操作之FMDB_第29张图片
效果图
数据库操作之FMDB_第30张图片
文件结构
  • MyViewController
import UIKit
import Alamofire
import Kingfisher

class MyViewController: UITableViewController {

    //MARK: - 属性
    //1.数据源数组
    lazy var dataArray:[DataModel] = {
       return [DataModel]()
    }()
    
    //2.任务队列
    lazy var queue:NSOperationQueue = {
       let tqueue = NSOperationQueue()
        //最大并发数
        tqueue.maxConcurrentOperationCount = 3
        return tqueue
    }()
    
    //3.数据库管理者
    let manager = FMDBManager.defaultManager
    
    //4.判断是否是第一次获取到的网络数据
    var isFirstNetData = true
    
    //MARK: - 生命周期
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //print(NSHomeDirectory())
        
        //FMDBManager().creatTable() //测试
        //测试创建数据库和表只执行了一次(测试此处时FMDBManager不是单例对象)
        //let fm = FMDBManager()
        //print(fm.db) //第一次会懒加载
        //print(fm.db) //第二次不会在执行创建表
        
        //测试
        //let tdataArray = self.manager.getAllData()
        //for item in tdataArray{
        //    print(item.title)
        //}
        
        //1.判断当前网络状态
        if self.hasNetWork(){
            //请求网络数据
            print("请求网络数据")//测试
            //网络请求成功之前用本地数据顶着
            self.dataArray = self.manager.getAllData()
            self.getNetData()
        }
        else{
            //获取本地数据
            print("使用本地数据")//测试
            self.dataArray = self.manager.getAllData()
        }
    }
}

//MARK: - 判断网络状态
extension MyViewController{
    func hasNetWork() -> Bool{
        //拿到当前的网络状态
        let status = Reachability.reachabilityForInternetConnection().currentReachabilityStatus()
        //判断网络状态
        if status == NotReachable{
            return false
        }
        return true
    }
}

//MARK: - 网络请求
extension MyViewController{
    
    func getNetData(){
        let urlStr = "http://0.0.0.0:[email protected]/api/articles/hot.json"
        Alamofire.request(.GET, urlStr, parameters: ["pn":0,"size":15], encoding: ParameterEncoding.URL, headers: nil).responseJSON(options: .MutableContainers) { (data) in
            //print(data)//测试
            
            //判断数据是否为空
            if let json = data.result.value{
                //拿到数组
                let articles = json.objectForKey("articles") as! [NSDictionary]
                
                //在第一次网络请求成功后移除通过本地获取的数据
                if self.isFirstNetData{
                    self.dataArray.removeAll()
                    self.isFirstNetData = false
                }
                
                //遍历数组
                for dict in articles{
                    //根据字典创建数据模型
                    let model = DataModel(dict: dict)
                    
                    //将数据存放到数据库中(异步最佳)
                    self.queue.addOperationWithBlock({
                        self.manager.insertData(model)
                    })
                    
                    //将模型存到数组中
                    self.dataArray.append(model)
                }
                
                //刷新tableView !!!
                self.tableView.reloadData()
            }
            else{
                print("网络请求失败")
            }
        }
    }
}

//MARK: - tabView协议方法
extension MyViewController{
    //1.设置cell个数
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.dataArray.count
    }
    //2.创建cell
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var cell = tableView.dequeueReusableCellWithIdentifier("cell")
        if cell == nil{
            cell = UITableViewCell(style: .Subtitle, reuseIdentifier: "cell")
        }
        //刷新数据
        let model = self.dataArray[indexPath.row]
        if model.img != nil{
            cell?.imageView?.kf_setImageWithURL(NSURL(string: model.img!)!, placeholderImage: nil)
        }
        cell?.textLabel?.text = model.title
        cell?.textLabel?.numberOfLines = 0
        cell?.detailTextLabel?.text = model.feed_title + "  " + model.time
        cell?.selectionStyle = .None
        return cell!
    }
    
    //3.设置cell高度
    override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return 120
    }
}
  • 数据库管理对象FMDBManager
import UIKit

class FMDBManager: NSObject {
    
    //MARK: - 属性
    
    //1.单例
    static let defaultManager = FMDBManager()
    private override init() {
        super.init()
    }
    
    //2.数据库
    //懒加载保证数据库只创建一次和打开一次
    lazy var db:FMDatabase = {
        //1.创建数据库
        //.db和.sqlite都是数据库文件后缀,随便选一个
        let path = NSHomeDirectory() + "/Documents/user.db"
        let tdb = FMDatabase(path: path)
        
        //2.打开数据库
        let ret = tdb.open()
        
        //判断
        if ret{
            print("数据库打开成功")
        }
        else{
            print("数据库打开失败")
        }
        
        //创建表
        //在懒加载中创建表保证只执行一次
        self.creatTable(tdb)
        
        return tdb
    }()
    
    //MARK: - 方法
    
    //MARK: - 创建表
    func creatTable(tdb:FMDatabase){
        let sqlStr = "CREATE TABLE IF NOT EXISTS t_DataModel(keyId integer PRIMARY KEY AUTOINCREMENT,feed_title text NOT NULL,id text NOT NULL UNIQUE,img text,time_t text NOT NULL,title text NOT NULL);"
        //执行sql语句
        let ret = tdb.executeUpdate(sqlStr, withArgumentsInArray: [])
        //判断
        if ret{
            print("建表成功")
        }
        else{
            print("建表失败")
            
        }
    }
    
    //MARK: - 将数据插入到数据库
    func insertData(model:DataModel){
        
        //创建sql语句
        let sqlStr = "INSERT INTO t_DataModel(feed_title,id,img,time_t,title) VALUES(?,?,?,?,?);"
        //执行结果
        var ret:Bool = false
        //执行sql语句
        if model.img == nil{
            ret = self.db.executeUpdate(sqlStr, withArgumentsInArray: [model.feed_title,model.id,"",model.time,model.title])
        }
        else{
            ret = self.db.executeUpdate(sqlStr, withArgumentsInArray: [model.feed_title,model.id,model.img!,model.time,model.title])
        }
        
        //判断
        if ret{
            print("数据插入成功")
        }
        else{
            print("数据插入失败")
            
        }
    }
    
    //MARK: - 获取指定数据
    func getData(page:Int,size:Int){
        //方案1:
        //获取到整张表的数据个数,算出约束的第一个值
        //方案2:
        //全部查询出来,逆序
        //let sqlStr = "SELECT * FROM t_DataModel LIMIT 0,20;"
    }
    
    //MARK: - 获取所有数据
    func getAllData() -> [DataModel]{
        var tempArray = [DataModel]()
        
        //创建查询语句
        let sqlStr = "SELECT * FROM t_DataModel;"
        
        //执行sql语句
        let dataSet = self.db.executeQuery(sqlStr, withArgumentsInArray: [])
        //遍历结果集合获取数据
        while dataSet.next(){
            //创建数据模型用来获取数据
            let model = DataModel()
            model.feed_title = dataSet.objectForColumnName("feed_title") as! String
            model.id = dataSet.objectForColumnName("id") as! String
            model.img = dataSet.objectForColumnName("img") as? String
            model.time = dataSet.objectForColumnName("time_t") as! String
            model.title = dataSet.objectForColumnName("title") as! String
            //存储数据
            tempArray.append(model)
        }
        
        return tempArray
    }
}
  • 数据模型DataModel
import UIKit

class DataModel: NSObject {

    //属性
    var feed_title = ""
    var id = ""
    var img:String? = nil
    var time = ""
    var title = ""
    //方法
    init(dict:NSDictionary) {
        self.feed_title = dict["feed_title"] as! String
        self.id = dict["id"] as! String
        self.img = dict["img"] as? String
        self.time = dict["time"] as! String
        self.title = dict["title"] as! String
    }
    
    override init() {
        super.init()
    }
}

你可能感兴趣的:(数据库操作之FMDB)