数据库基本知识

01,数据库简介

什么是数据库

  • 数据库:Database 是按照数据结构来组织,存储和管理数据的仓库
  • 分为2大种类
  • 关系型数据库(主流)
    • pc端:
    • 嵌入式/移动客户端 : SQLite
  • 对象型数据库

iOS中数据的存储方式

  • plist(NSArray/NSDictionary)
  • 只能存储系统自带的数据类型,自定义的对象无法储存
  • preference(偏好设置/NSUserDefaults)
  • 本质就是一个plist文件
  • NSCoding(NSKeyedArchiver/NSKeyedUnarchiver)
  • 可以存储自己定义的数据类型,但是都是一次性的全数据操作
  • SQLite3
  • 存储一些大批量的数据,排序,统计等操作
  • Core Data
  • 对SQLite3的一层面向对象的包装,本质还是转化为SQL语句去执行

什么是SQLite

  • SQLite是一款轻量级的嵌入式数据库
  • 占用资源非常低,在嵌入设备中,只需要几百K就行了
  • 处理速度快

如何存储数据到数据库

  • 数据库的存储结构和excle很像,以表(table)为单位
  • 数据库存储数据的步骤:
  • 新建数据库文件
  • 新建一张表:table
  • 添加多个字段:column 列 属性
  • 添加多行记录:row 每行存放多个字段对应的值

02.Navicat软件


  • 是一套适用于MySQL,SQLite等多个数据库系统的图形化数据库管理,报告以及箭筒的工具
  • 通过软件可以演练创建/删除表,查询/删除/修改记录操作的SQL

03.软件的基本使用

  • 表里面应该有个"主键",能标识唯一的一行
  • 解决方案:重新编辑表结构,设置主键(自增长)
  • 理论基础:
  • 1.表格组成:行(记录)和列(属性)"属性" 是用来标识这一列应该存放什么
    "记录" 是用来存放一条数据
  • 2.属性类型:
  • blob:二进制类型
  • integer:整型
  • real:浮点型
  • text:文本类型
  • null:空类型
  • 3.主键:
  • 主键(primary key /PK)用来位移标识某一条记录
  • 主键可以使一个字段或者多个字段:行和列
  • 设计原则:1>应当对用户没有意义,2>永远也不要更新主键3>主键不应包含动态变化的数据4>主键应当有计算机自动生成

04.SQL语言简介

什么是SQL?

  • SQL(structured query language):结构化查询语言
  • SQL是一种对关系性数据苦衷的数据进行定义和操作的语言

SQL语句

  • 使用SQL语言编写出来的句子/代码就是SQL语言
  • 在程序中如果想要操作(增删改查 CRUD)数据库中的数据,就必须使用SQL语言
  • Create ,Retrive,Updata,Delete

SQL语句的特点

  • 不区分大小写
  • 每条语句以;结尾

SQL中常用的关键字

SQL语句的种类

1.数据定义语句(DDL : Data Definition Language)

  • 包括create,drop,Alert等操作
  • 在数据库中创建新表或者删除表(create table 和 drop table)

2.数据操作语句(DML : Data Manipulation Language)

  • 包括insert.,delete,updata等操作
  • 上面的3种操作分别用于添加,修改,删除表中的数据

3.数据查询语句(DQL : Data Query Language)

  • 可以用于查询获得表中的数据
  • 关键字select是DQL用的最多的操作
  • 其他DQL常用的关键字where,order by,group by 和 having

05.DDL语句

创建表

  • 格式: create table 表名 (字段名1 字段类型1 ....);
  • 示例: create table t_stu(id integer,name text,age integer,score real);
  • 经验:
  • 实际上SQLite是无类型的
  • 就算申明为某种类型,但是还是可以存储其他类型的(主键除外)
  • 但是为了保证编程规范,方便交流,最好加上类型
  • 语句优化:
  • 创建表格时,最好加上判断这个表格是否存在,防止语句多次执行发生错误
  • create table if not exists 表名(字段名1 字段类型1 ....)

删除表

  • 格式: drop table 表名; drop table if exists 表名;
  • 示例: drop table t_stu;
  • 语句优化:最好加个判断,防止语句多次执行发生错误
  • drop table if exists 表名;

修改表

  • 注意: SQLite里面只能实现Alter Table的部分功能,不能删除一列,修改一个已经存在的列名
  • 修改表名:ALTER TABLE 旧表名 REMANE TO 新表名
  • 新增属性:ALTER TABLE 表名 ADD COLUMN 列名 数据类型 限定符

06.约束

简单约束

  • 不能为空: not null
  • 不能重复:uinque
  • 默认值:default
  • 示例:create table t_stu (id integer ,name text not null unique,age integer not null default 1);

主键约束

  • 添加主键约束的原因:
  • 如果t_stu表中就name和age连个字段,而且有些记录的name和age字段的值一样,没办法区分这些数据,造成数据录的记录不唯一,不方便管理数据,应该保证每条记录的唯一性,所以增加了主键约束
  • 每张表都必须有一个主键,用来标示记录的唯一性
  • 主键:Primary Key :用来唯一的标示某一条记录
  • 示例:creat table t_stu (id integer primary key autoincrement,name text);

07.DML语句

插入语句:insert

  • 格式:insert into 表名(字段1,字段2...) value(字段1值,字段2值...);
  • 示例:insert into t_stu(name,age) value('liuwei',19);
  • 注意:数据库中的字符串内容应该用单引号括住

更新语句:update

  • 格式:update 表名 set 字段1 = 字段1的值,字段2 = 字段2的值,...;
  • 示例:update t_stu set name = 'wen',age = 20;
  • 注意:示例会将t_stu中的所有的记录中的那么都改为wen,age都改为20

删除语句:delete

  • 格式:delete from 表名;
  • 示例:delete from t_stu;
  • 注意:示例会将t_stu表中所有的记录都删除

08.条件语句

作用

  • 如果只想更新或者删除某些固定的记录,那就必须在DML语句加上一些条件

常见格式

  • where 字段 = 某个值;//不能使用两个==
  • where 字段 is 某个值;//is 相当于 =
  • where 字段 != 某个值 ;
  • where 字段 is not 某个值 ; // is not 相当于 !=
  • where 字段 > 某个值 ;
  • where 字段1 = 某个值 and 字段2 > 某个值 ; // and相当于C语言中的 &&
  • where 字段1 = 某个值 or 字段2 = 某个值 ; // or 相当于C语言中的 ||

小试牛刀

  • 将t_student表中年龄大于10 并且 姓名不等于wex的记录,年龄都改为 5
  • update t_student set age = 5 where age > 10 and name != 'wex';
  • 删除t_student表中年龄小于等于10 或者 年龄大于30的记录
  • delete from t_student where age <= 10 or age > 30;
  • update t_student set score = age where name = ‘wex’ ;
  • 将name = 'wex'的人的score的值改为age的值

09DQL

格式

  • select 字段1,字段2,...from 表名;
  • select * from 表名;//查询所有的字段
  • 示例:
  • select name, age from t_student ;
  • select * from t_student ;
  • select * from t_student where age > 10 ; // 条件查询

10查询相关语句

统计

  • count(X)
  • select count(*) from t_student //计算所有记录个数
  • select count(age) from t_student //计算age有值的记录个数(Null不计算在内)
  • avg(X)
  • 计算某个字段的平均值
  • sum(X)
  • 计算某个字段的总和
  • max(X)
  • 计算某个字段的最大值
  • min(X)
  • 计算某个字段的最小值

排序

  • 查询出来的结果可以用order by进行排序
  • select 字段1, 字段2 from 表名 order by 字段 ;
  • select * from t_student order by age ;
  • 默认是按照升序排序(由小到大),也可以变为降序(由大到小)
  • select * from t_student order by age desc ; //降序
  • select * from t_student order by age asc ; // 升序(默认)
  • 也可以用多个字段进行排序
  • select * from t_student order by age asc, height desc ;
  • 先按照年龄排序(升序),年龄相等就按照身高排序(降序)

limit分页

  • 使用limit可以精确地控制查询结果的数量,比如每次只查询10条数据
  • 格式:select * from 表名 limit 数值1, 数值2 ;
  • 示例:select * from t_student limit 4, 8 ;//可以理解为:跳过最前面4条语句,然后取8条记录
  • 分页:
  • limit常用来做分页查询,比如每页固定显示5条数据,那么应该这样取数据
    • 第1页:limit 0, 5 第2页:limit 5, 5 第3页:limit 10, 5 第n页:limit 5*(n-1), 5
  • 特殊案例
    • select * from t_student limit 7 ;
    • 相当于select * from t_student limit 0, 7 ;
    • 表示取最前面的7条记录

11多表查询

多表查询

  • select 字段1, 字段2, … from 表名1, 表名2 ;

别名

  • select
    别名1.字段1 as 字段别名1,
    别名2.字段2 as 字段别名2,

    from
    表名1 as 别名1,
    表名2 as 别名2 ;
  • 可以给表或者字段单独起别名
  • as 可以省略

表连接查询

  • select 字段1, 字段2, … from 表名1, 表名2 where 表名1.id = 表名2.id;

外键

  • 如果表A的主关键字是表B中的字段,则该字段称为表B的外键
  • 保持数据一致性,完整性,主要目的是控制存储在外键表中的数据。 使两张表形成关联,外键只能引用外表中的列的值或使用空值。

12-代码实现SQLite-DDL

  • 导入框架 导入系统框架sqlite3.tbd(sqlite3.dylib)
  • 建立桥接文件, 导入头文件sqlite3.h
  • 代码实现:
    1. 打开数据库
    1. 使用打开的数据库, 执行DDL语句, 创建一个数据库表
    1. 将数据库操作封装成一个工具类
class SQLiteTool: NSObject {

    static let shareInstance = SQLiteTool()
    
    var db: COpaquePointer = nil
    override init() {
        super.init()
        
        // 1. 打开数据库
        // 参数1: 数据库路径
        // 参数2: 一个打开的数据库的指针(后期操作所有的sql语句, 都是使用这个对象)
        // 根据一个路径, 打开一个数据库(如果路径不存在, 则创建一个数据库, 如果存在, 则直接打开)
        // 关于sqlite数据库的后缀名, 没有一个明确的要求, 随便写
        // db, db3, sqlite
        let path = "/Users/xiaomage/Desktop/db/demo.sqlite"

        if sqlite3_open(path, &db) != SQLITE_OK {
            print("打开数据库失败")
        }else {
            print("打开数据库成功")
            createTable()
        }

    }
 func dropTable() -> () {
        
        // 理论基础: 如果想要操作表或者操作记录, 统一都是分两个步骤
        // 步骤1: 创建sql语句(因为我们操作数据库, 都必须使用sql语句才能操作)
        // 步骤2: 执行sql语句
        
        let sql = "drop table if exists t_stu"
        
        if excuteSql(sql) {
            print("执行成功")
        }
        
        
    }
    
    
    func createTable() -> () {
        // 1. 写sql语句
        let sql = "create table if not exists t_stu(id integer primary key autoincrement, name text not null, age integer, score real default 60)"
        if excuteSql(sql) {
            print("执行成功")
        }
        
        
    }
    
    func excuteSql(sql: String) -> Bool {
        // 2. 执行sql语句
        // 功能, 执行sql字符串
        // 参数1: 一个已经打开的数据库(代表操作的是哪一个数据库)
        // 参数2: sql语句
        // 参数3: 回调函数 nil
        // 参数4: 参数3: 回调函数里面的参数1 nil
        // 参数5: 错误信息 nil
        return sqlite3_exec(db, sql, nil , nil , nil) == SQLITE_OK
    }

13-代码实现DML语句-Insert

class Student: NSObject {
    
    var name : String = ""
    var age : Int = 0
    var score : Double = 0.0
    
    override init() {
        super.init()
    }
    
    init (name : String , age : Int, score : Double){
    
        self.name = name
        self.age = age
        self.score = score
    
    }
func insertStu() -> () {
        
        let sql = "insert into t_stu (name ,age ,score) values ('\(name)',\(age),\(score))"
        
        if SQLiteTool.shareInstance.excuteSql(sql) {
            print("插入成功")
        }else{
            print("插入失败")
        }
        
    }
    
   class  func deletStu(name : String) -> () {
        
        let sql = "delete from t_stu where name = '\(name)'"
        
        if SQLiteTool.shareInstance.excuteSql(sql) {
            print("删除成功")
        }else{
            print("删除失败")
        }
    }
    
    func updateStu (newStu : Student) -> () {
        
        let sql = "update t_stu set name = '\(newStu.name)',age = \(newStu.age),score = \(newStu.score) where name = '\(name)'"
        
        if SQLiteTool.shareInstance.excuteSql(sql) {
            print("更改成功")
        }else{
            print("更改失败")
        }

14-代码实现DML语句-Insert绑定参数

准备语句(prepared statement)对象

  • 准备语句(prepared statement)对象一个代表一个简单SQL语句对象的实例,这个对象通常被称为“准备语句”或者“编译好的SQL语句”或者就直接称为“语句”。

操作历程

    1. 使用sqlite3_prepare_v2或相关的函数创建这个对象
    1. 使用sqlite3_bind_*()给宿主参数(host parameters)绑定值
    1. 通过调用sqlite3_step() 一次或多次来执行这个sql
    1. 使用sqlite3_reset()重置这个语句,然后回到第2步,这个过程做0次或多次
    1. 使用sqlite3_finalize()销毁这个对象, 防止内存泄露
 
    func insertBind() -> () {
        let sql = "insert into t_stu(name, age, score) values (?, ?, ?);"
        
        // 1. 创建"准备语句"
        // 参数1: 一个打开的数据库
        // 参数2: sql字符串
        // 参数3: 取出参数2 的长度 3 -1 代表自动计算
        // 参数4: 指向"准备语句的指针"
        // 参数5: 通过参数3指定的长度, 取出参数2, 字符串之后, 剩余的字符串 nil
        let db = SQLiteTool.shareInstance.db
        var stmt: COpaquePointer = nil
        if sqlite3_prepare_v2(db, sql, -1, &stmt, nil) != SQLITE_OK {
            print("准备语句创建失败")
            return
        }
        
        // 2. 绑定数据
        // 不同的数据类型, 绑定的方法不一样
        // 绑定姓名- 字符串
        // 参数1: 准备语句
        // 参数2: 绑定的索引 从1开始
        // 参数3: 绑定的值
        // 参数4: 代表, 值取出的长度 -1 自动计算
        // 参数5: 指向函数的指针: 参数的处理方式
        // #define SQLITE_STATIC      处理方式: 不对参数做任何操作(认为参数是一个static)
        // #define SQLITE_TRANSIENT   处理方式: 会对参数, 做一个强引用, 然后, 使用完毕之后, 在合适的时候释放
        // 使用这个函数一定要注意: 需要明确的知道最终的确切类型是什么
         let SQLITE_TRANSIENT = unsafeBitCast(-1, sqlite3_destructor_type.self)
        sqlite3_bind_text(stmt, 1, "lisi---3", -1, SQLITE_TRANSIENT)
        
        
        // 绑定年龄 Int
        sqlite3_bind_int(stmt, 2, 18)
        
        // 绑定分数 - Double
        sqlite3_bind_double(stmt, 3, 99)
        
        // 3. 执行"准备语句"
        
        if sqlite3_step(stmt) == SQLITE_DONE {
            print("执行成功")
        }else {
            print("执行失败")
        }
        
        // 4. 重置"准备语句"
        sqlite3_reset(stmt)
        
        
        // 5. 释放资源
        sqlite3_finalize(stmt)
        
        
    }
 
    }

15-DML语句-Insert插入数据优化

  • 测试结果分析

  • sqlite_exec 直接执行 和 未拆解"准备语句" 执行 执行时间平均差不多

  • 拆解后的"准备语句" 执行, 效率明显高了一些

  • 虽然按步骤使用"准备语句", 但是执行效率,依然非常低, 达到了5秒左右, 不可原谅

    • 原因分析:每当SQL调用执行方法执行一个语句时, 都会开启一个叫做"事务"的东西, 执行完毕之后再提交"事务";
      也就是说, 如果执行了10000次SQL语句, 就打开和提交了10000次"事务", 所以造成耗时严重
    • 解决方案:只要在执行多个SQL语句之前, 手动开启事务, 在执行完毕之后, 手动提交事务, 这样 再调用SQL方法执行语句时, 就不会再自动开启和提交事务
  • 结论

    1. 如果插入大量数据, 请务必手动开启/提交事务
    1. 根据不同情况, 选择使用sqlite3_exec 或者 "准备语句"
    • 单条语句, 前者, 因为使用简单
    • 大批量插入, 选择后者
    // 优化方案: 
    // 如果大批量插入数据
    // 方案: sqlite3_step() 准备语句
    // 方案: sqlite3_exec() sql字符串
    
    // 优化方案1: sqlite3_step() 准备语句 分解版
    // 优化方案2: 
    // sqlite3_step() sqlite3_exec() 这两个函数执行, 内部都会自动开启一个事务, 然后执行完毕之后, 提交事务 , 开启/提交, 整个过程非常耗费时间
    // 只要我们手动的开启事务, 手动的提交事务, 那么在函数内部, 就不会自动开启和提交事务
  
  • 工具类中,添加了两个方法,用来手动开启事务和提交事务
    func beginTransaction() -> () {
        let sql = "begin transaction"
        excuteSql(sql)
    }
    
    func commitTransaction() -> () {
        let sql = "commit transaction"
        excuteSql(sql)
    }

  • 在执行绑定数据前手动开启事务
 SQLiteTool.shareInstance.beginTransaction()
        
        for _ in 0..<10000 {
  • 在重置准备语句后手动关闭事务
            // 4. 重置"准备语句"
            sqlite3_reset(stmt)
        }
        
        SQLiteTool.shareInstance.commitTransaction()

16-代码实现-事务

概念

  • 事务(Transaction)是并发控制的单位,是用户定义的一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位。通过事务,可以将逻辑相关的一组操作绑定在一起,保持数据的完整性。
  • 事务通常是以BEGIN TRANSACTION开始,以COMMIT TRANSACTION或ROLLBACK TRANSACTION结束。

小试牛刀

  • 在工具类方法中添加一个rollbackTransaction的方法
    func rollBackTransaction() -> () {
        let sql = "rollback transaction"
        excuteSql(sql)
    }
  • 在学生类中增加一个更新分数的方法
   class func updateScore(sql : String) -> Bool {
    
        return SQLiteTool.shareInstance.excuteSql(sql)
    }
  • 在点击屏幕时做操作,当两个操作都完成时才会commit,否则rollback
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
   
        SQLiteTool.shareInstance.beginTransaction()
        
        let result1 = Student.updateScore("update t_stu set score = score - 9 where name = 'liuwei'")
        let result2 = Student.updateScore("update t_stu set score = score + 9 where name = 'wenxiaoli'")
        
        if result1 && result2 {
            SQLiteTool.shareInstance.commitTransaction()
        }else{
            SQLiteTool.shareInstance.rollbackTransaction()
        }
    }

17-代码实现DQL语句

方式1: sqlite3_exec

  • 作用: 可以通过回调来获取结果, 步骤相对来说简单, 结果数据类型没有特定类型(id)
    class func queryAll() -> () {
        let sql = "select * from t_stu"
        // 参数1: 一个已经打开的数据库
        // 参数2: sql字符串
        // 参数3: 回调 (一般存放查询的结果集)
                // 参数1: 参数4的值
                // 参数2: 列的个数
                // 参数3: 值(字符串)的数组
                // 参数4: 列名(字符串)组成的数组
                // 返回值: 0 继续查询, 非零, 终止查询
        
        // 参数4: 参数3的参数1
        // 参数5: 错误信息
        let db = SQLiteTool.shareInstance.db
        
        sqlite3_exec(db, sql, { (param, columnCount, values, columnNames) -> Int32 in
            
            let count = Int(columnCount)
            for i in 0..<count {
                
                let columName = columnNames[i]
                let columnNameStr = String(CString: columName, encoding: NSUTF8StringEncoding)
                
                let value = values[i]
                let valueStr = String(CString: value, encoding: NSUTF8StringEncoding)
                
                print(columnNameStr, valueStr)
                
            }
            return 0
            }, nil, nil)
    }

方式2: 通过"准备语句"

  • 作用: 可以处理不同特定类型, 步骤相对来说复杂
  • 步骤:
    1. 预处理函数 获取"准备语句"
    1. 不断执行"准备语句", 直到无结果集
    1. 获取列的类型
    1. 根据每列的类型取出不同的值
    1. 释放资源
   class func queryAllStmt() -> () {
   
       let sql = "select * from t_stu"
       // 准备语句操作流程
       // 1. 创建"准备语句"
       let db = SQLiteTool.shareInstance.db
       var stmt: COpaquePointer = nil
       if sqlite3_prepare_v2(db, sql, -1, &stmt, nil) != SQLITE_OK {
           print("预处理失败")
           return
       }
       // 2. 绑定数据(这一步可以省略)
       // 3. 执行SQLITE_DONE 适用于删除, 或者更新, 或者插入
       // 查询不是使用这个标志
       // 有一个指针, 指向当前的记录, 当没执行一次,这个方法, 都会查询下一条还有没有数据, 如果有, 返回值是SQLITE_ROW, 并且, 把查询的结果放到"准备语句里面", 所以, 如果想要获取一行里面的数据, 应该从"准备语句里面获取"
       while sqlite3_step(stmt) == SQLITE_ROW {
           
           // 遍历一行的每一列
           // 1. 获取总共有多少列
           let count = sqlite3_column_count(stmt)
           
           // 2. 遍历每一列
           for i in 0..<count {
               // 2.1 获取列的名称
               // 参数1: 准备语句
               // 参数2: 索引
               // UnsafePointer<Int8>
               let columnName = sqlite3_column_name(stmt, i)
               let columnNameStr = String(CString: columnName, encoding: NSUTF8StringEncoding)
               print(columnNameStr)
               
               // 2.2 获取列的数值
               // 不同的数据类型, 应该使用不同的函数进行获取
               // 2.2.1 获取列的类型
               let type = sqlite3_column_type(stmt, i)
               // 2.2.2 根据不同的类型, 使用不同的函数, 进行获取响应的值
               if type == SQLITE_INTEGER {
                   let value = sqlite3_column_int(stmt, i)
                   print(value)
               }
               
               if type == SQLITE_FLOAT {
                   let value = sqlite3_column_double(stmt, i)
                   print(value)
               }
               
               if type == SQLITE_TEXT {
                   // UnsafePointer<UInt8>
                   let value = UnsafePointer<CChar>(sqlite3_column_text(stmt, i))
                   // UnsafePointer<CChar>
                   let valueStr = String(CString: value, encoding: NSUTF8StringEncoding)
                   print(valueStr)
               }
           }
       }
       
       // 4. 重置(这一步可以省略)
       // 5. 释放资源
   }

18-FMDB基本使用

1. 什么是FMDB?

  • FMDB是iOS平台的SQLite数据库框架
  • FMDB以OC的方式封装了SQLite的C语言API

2. FMDB有什么优势?

  • 使用起来更加面向对象,省去了很多麻烦、冗余的C语言代码
  • 提供了多线程安全的数据库操作方法,有效地防止数据混乱

3. 安装方式

  • Cocoapods
  • 手动集成(swift)
    1. 导入FMDB文件
    1. 导入系统依赖库sqlite3.0.tbd
    1. 建立桥接文件, 并导入需要的头文件

核心类

  • FMDatabase

  • 一个FMDatabase对象就代表一个单独的SQLite数据库

  • 用来执行SQL语句

  • FMResultSet

  • 使用FMDatabase执行查询后的结果集

  • FMDatabaseQueue

  • 用于在多线程中执行多个查询或更新,它是线程安全的

使用步骤

    1. 打开数据库
  • 通过指定SQLite数据库文件路径来创建FMDatabase对象
  • 文件路径有三种情况
    • 具体文件路径:如果不存在会自动创建
    • 空字符串@"":会在临时目录创建一个空的数据库,当FMDatabase连接关闭时,数据库文件也被删除
    • nil:会创建一个内存中临时数据库,当FMDatabase连接关闭时,数据库会被销毁
  • FMDatabase *db = [FMDatabase databaseWithPath:path];
  • if ([db open]) { NSLog(@"打开成功!"); }
    static let shareInstance = FMDBTool()
   
   lazy var db: FMDatabase = {
       // 1. 创建或者打开一个数据库
       let path = "/Users/xiaomage/Desktop/fmdb/demo.sqlite"
       let db = FMDatabase(path: path)
       return db
   }()
   
   override init() {
       super.init()

       if db.open() {
           print("数据库打开成功")
       }

   }
    1. 执行更新
  • 在FMDB中,除查询以外的所有操作,都称为“更新”:create、drop、insert、update、delete等
  • 使用executeUpdate:方法执行更新:
      • (BOOL)executeUpdate:(NSString*)sql, ...
      • (BOOL)executeUpdateWithFormat:(NSString*)format, ...
      • (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments
  • 示例:[db executeUpdate:@"UPDATE t_student SET age = ? WHERE name = ?;", @20, @"Jack"]
func createTable() -> () {
        
        let sql = "create table if not exists t_stu(id integer primary key autoincrement, name text not null, age integer, score real default 60)"
        
        if db.executeUpdate(sql, withArgumentsInArray: nil) {
            print("创建表成功")
        }else {
            print("失败")
        }
        
        
        
    }
    
    func dropTable() -> () {
        
        let sql = "drop table if exists t_stu"
        
        if db.executeUpdate(sql, withArgumentsInArray: nil) {
            print("成功")
        }else {
            print("失败")
        }

   
    }
    
    func insertStu() -> () {
        let sql = "insert into t_stu(name, age, score) values ('zhangsan', 18, 99)"
        if db.executeUpdate(sql, withArgumentsInArray: nil) {
            print("成功")
        }else {
            print("失败")
        }
        
    }
    
    func deleteStu() -> () {
        let sql = "delete from t_stu where name = 'zhangsan'"
        if db.executeUpdate(sql, withArgumentsInArray: nil) {
            print("成功")
        }else {
            print("失败")
        }
    }
    
    
    func updateStu() -> () {
        let sql = "update t_stu set age = 999 where name = 'zhangsan'"
        if db.executeUpdate(sql, withArgumentsInArray: nil) {
            print("成功")
        }else {
            print("失败")
        }
    }

    1. 执行查询
  • 查询方法:
      • (FMResultSet )executeQuery:(NSString)sql, ...
      • (FMResultSet )executeQueryWithFormat:(NSString)format, ...
      • (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments
    func queryAll() -> () {
        let sql = "select * from t_stu"
        let resultSet = db.executeQuery(sql, withArgumentsInArray: nil)
        while resultSet.next() {
            let age = resultSet.intForColumn("age")
            let name = resultSet.stringForColumn("name")
            let score = resultSet.doubleForColumn("score")
            print(age, name, score)
        }
    }
    1. 关闭数据库
  • database.close()

19-FMDabaseQueue

  • FMDatabase这个类是线程不安全的,如果在多个线程中同时使用一个FMDatabase实例,会造成数据混乱等问题
  • 为了保证线程安全,FMDB提供方便快捷的FMDatabaseQueue类
  • FMDatabaseQueue的创建:FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:path];
    static let shareInstance = FMDBTool()
    
    lazy var queue: FMDatabaseQueue = {
        let path = "/Users/xiaomage/Desktop/fmdb/demo.sqlite"
        let queue = FMDatabaseQueue(path: path)
        return queue
        
    }()
    
//    lazy var db: FMDatabase = {
//        // 1. 创建或者打开一个数据库
//        let path = "/Users/xiaomage/Desktop/fmdb/demo.sqlite"
//        let db = FMDatabase(path: path)
//        return db
//    }()
//
    override init() {
        super.init()

//        if db.open() {
//            print("数据库打开成功")
//        }
 
    }
    
    
    func createTable() -> () {
        
        let sql = "create table if not exists t_stu(id integer primary key autoincrement, name text not null, age integer, score real default 60)"
        
        queue.inDatabase { (db: FMDatabase!) in
            if db.executeUpdate(sql, withArgumentsInArray: nil) {
                print("创建表成功")
            }else {
                print("失败")
            }
        }
        
        
        
        
        
    }
    
    func dropTable() -> () {
        
        let sql = "drop table if exists t_stu"
        
        queue.inDatabase { (db: FMDatabase!) in
            
            if db.executeUpdate(sql, withArgumentsInArray: nil) {
                print("成功")
            }else {
                print("失败")
            }

        }
        
   
    }
    
    func insertStu() -> () {
        let sql = "insert into t_stu(name, age, score) values ('zhangsan', 18, 99)"
        queue.inDatabase { (db: FMDatabase!) in
            if db.executeUpdate(sql, withArgumentsInArray: nil) {
                print("成功")
            }else {
                print("失败")
            }

        }
        
    }
    
    func deleteStu() -> () {
        let sql = "delete from t_stu where name = 'zhangsan'"
        queue.inDatabase { (db: FMDatabase!) in
            if db.executeUpdate(sql, withArgumentsInArray: nil) {
                print("成功")
            }else {
                print("失败")
            }
        }
       
    }
    
    
    func updateStu() -> () {
        let sql = "update t_stu set age = 999 where name = 'zhangsan'"
        queue.inDatabase { (db: FMDatabase!) in
            if db.executeUpdate(sql, withArgumentsInArray: nil) {
                print("成功")
            }else {
                print("失败")
            }
        }
        
    }
    
    func queryAll() -> () {
        let sql = "select * from t_stu"
        queue.inDatabase { (db: FMDatabase!) in
        let resultSet = db.executeQuery(sql, withArgumentsInArray: nil)
        while resultSet.next() {
            let age = resultSet.intForColumn("age")
            let name = resultSet.stringForColumn("name")
            let score = resultSet.doubleForColumn("score")
            print(age, name, score)
        }
        }
    }
    
    
    func transactionTest() -> () {
        queue.inTransaction { (db: FMDatabase!, rollback) in
            
            let sql = "update t_stu set score = score + 10 where name = 'zhangsan'"
            let sql2 = "update t_stu set score2 = score - 10 where name = 'lisi'"
            let result1 = db.executeUpdate(sql, withArgumentsInArray: nil)
            let result2 = db.executeUpdate(sql2, withArgumentsInArray: nil)
            
            if result1 && result2 {
                
            }else {
                
                // 回滚 *rollback = rollback.memory
                rollback.memory = true
                
            }
            
            
        }
    }
    
    func stamentsTest() -> () {
        let sql = "insert into t_stu(name, age, score) values ('zhangsan3', 18, 99);insert into t_stu(name, age, score) values ('zhangsan2', 18, 99);"
        queue.inDatabase { (db) in
            db.executeStatements(sql)
        }
    }

小礼物走一走,来简书关注我



作者:天润
链接:http://www.xingzuji.com/
來源:行足迹旅游
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
posted on 2018-01-17 22:28  行足迹旅游  阅读(248)  评论(0编辑  收藏  举报