Skip to content

zhoufusong/FMDBTestDemo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

在swift项目中使用FMDB操作SQlite数据库

SQlite是一个轻量级的关系数据库,IOS只需要加入libsqlite3.dylib及头文件即可支持SQlite数据库,但是原生的 SQLite API 在使用上相当不友好,易用性不足,所以出现了很多基于SQLite API的封装库,FMDB就是其中比较简洁易用的代表。它是iOS平台的SQlite数据库框架,以OC的方式封装了SQlite的C语言API,使其更加简单易用。另外,FMDB 同时兼容 ARC 和非 ARC 工程,会自动根据工程配置来调整相关的内存管理代码。

优点是:

  • 以OC方式封装SQlite的C语言API,使用方便
  • 轻量级框架,使用灵活
  • 线程安全

缺点是:

安装方式:

Cocoapods或者手动导入,同时添加Sqlite3的依赖包,桥接文件

核心类:

  • FMDatabase

    一个FMDatabase代表一个SQlite数据库,可用于各种SQL命令操作

    • executeStatements: 执行多条语句
    • executeQuery: 执行查询语句
    • executeUpdate: 执行除查询外其他操作,如create、insert、delete、update等
  • FMDatabaseQueue

    在多个线程中执行查询或者更新,保证线程安全

    • inDatabase: 参数是一个闭包, 在闭包里面传入FMDatabase对象
    • inTransaction: 使用事物
  • FMResultSet

    使用FMDatabase查询后的结果集,可以通过字段名称获取字段值

使用方法:

  • 创建

    • 当指定路径的数据库文件不存在时,会自动创建。
    • 路径参数为空字符串,会在临时文件目录下创建这个数据库,数据库断开连接时,数据库文件被删除。
    • 路径参数为NULL,会建立一个在内存中的数据库,数据库断开连接时,数据库文件被删除
    //定义路径
    let documentPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).last! as NSString
    let dbpath = documentPath.appendingPathComponent("fmdbUser.db")
    let db = FMDatabase(path: dbPath)
    //打开数据库
    if(db.open()){
      //some operation
      db.close()//关闭数据库
    }else{
      //error
    }
    
  • 增删查改

    • 打开操作失败,可能是权限不足或者资源不足。通常打开完操作操作后,需要调用 close 方法来关闭数据库
    • 更新:executeUpdate,错误可以使用error参数API,除了select的所有操作基本都是使用executeUpdate
    let sql = "insert into user (name , password) values(?,?)"
    let res = db.executeUpdate(sql,withArgumentsIn: [name, "boy"])
    
    • 查询:executeQuery, 即使操作结果只有一行,也需要先调用 FMResultSet 的 next 方法。
    let sql = "select * from user"
    let rs = db.executeQuery(sql, withArgumentsIn: [])//FMResultSet
    while (rs?.next())! {
        let userId = rs?.int(forColumn: "id")
        let name = rs?.string(forColumn: "name")
        let pass = rs?.string(forColumn: "password")
        print("user id = \(String(describing: userId)), name = \(String(describing: name)), pass = \(String(describing: pass))")
    }
    db.close();
    

    FMDB 提供如下多个方法来获取不同类型的数据:

    intForColumn:
    longForColumn:
    longLongIntForColumn:
    boolForColumn:
    doubleForColumn:
    stringForColumn:
    dateForColumn:
    dataForColumn:
    dataNoCopyForColumn:
    UTF8StringForColumnIndex:
    objectForColumn:
    

    除了根据字段获取数据,还可以用对应的ForColumnIndex根据字段位置来获取

    通常情况下,并不需要关闭 FMResultSet,因为相关的数据库关闭时,FMResultSet 也会被自动关闭。

    数据参数可以使用标准SQL语句,用 ? 表示执行语句的参数,在具体方法中传入参数

  • 多线程操作

    如果需要多线程操作数据库,不能在多个线程中共同一个 FMDatabase 对象并且在多个线程中同时使用,这个类本身不是线程安全的,这样使用会造成数据混乱等问题,正确的方法是使用FMDatabaseQueue来保证线程安全。首先用一个数据库文件地址来初使化 FMDatabaseQueue,然后就可以将一个闭包 (block) 传入 inDatabase 方法中(事务的话是inTransaction)。

        guard let dbPath = self.dbPath else{
                return;
            }
            
            let queue = FMDatabaseQueue.init(path: dbPath)
            let q1 = DispatchQueue.init(label: "queue1")
            let q2 = DispatchQueue.init(label: "queue2")
            
            q1.async {
                for i in 0..<100{
                    queue.inDatabase{ db in
                        let sql = "insert into user (name, password) values(?, ?) "
                        let name = String.init(format: "queue111 %d", i)
                        let res = db.executeUpdate(sql, withArgumentsIn: [name,"boy"])
                        if !res{
                            print("error to add db data: \(name)")
                        }else{
                            print("success to add db data: \(name)")
                        }
                    }
                }
            }
            
            q2.async {
                for i in 0..<100{
                    queue.inDatabase{ db in
                        let sql = "insert into user (name, password) values(?, ?) "
                        let name = String.init(format: "queue222 %d", i)
                        let res = db.executeUpdate(sql, withArgumentsIn: [name,"boy"])
                        if !res{
                            print("error to add db data: \(name)")
                        }else{
                            print("success to add db data: \(name)")
                        }
                    }
                }
            }
    
    

    还有很多SQL操作和FMDB的API并没有提及到,需要平时多实践,另外相比CoreData和SQLite API,使用起来方便很多。

About

FMDB test

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published