Swift SQLite ORM 框架 - GRDB.swift 使用

简介

在 OC 中我们经常使用 FMDB 以及一些系列衍生的 Model 工具来操作数据库, 但在Swift中显得不那么友好.

  1. Swift 与 OC 混编中 ClassName 变成项目名.类名, 这种情况下操作数据库会出现各种各样的问题.
  2. 必须要继承 NSObject, 不适合 Struct 作为Model 的情况.

GRDB.swift 是 Swift 用来操作 SQLite 的工具. 通过 Protocol 的方式, 对 Struct Class 进行 CURD 操作, 同样也可以使用 DML 操作数据.


创建连接数据库

		var dbPool: DatabasePool?
		var dbQueue: DatabaseQueue?
        do {
            dbPool = try DatabasePool(path: path)
            dbQueue = try DatabaseQueue(path: path)
        }catch {
            
        }

DatabasePool 支持并发数据库操作 和 WAL模式.推荐使用.


执行SQL语句操作

创建表
		guard let cursor = dbPool else {
            return
        }
        
        do {
            
            try cursor.write({ (db) in
                try db.execute(sql: """
                        CREATE TABLE IF NOT EXISTS user (
                        id INTEGER PRIMARY KEY AUTOINCREMENT,
                        name TEXT,
                        age INTEGER,
                        address TEXT)
                        """
                )
            })
        }catch {
            debugPrint("create table user error")
        }
创建索引
			try cursor.write({ db in
                let res = try db.indexes(on: "user").filter({$0.name == "name_index"}).isEmpty
                if res {
                    try db.create(index: "name_index", on: "user", columns: ["name"])
                }
            })
删除索引
			try cursor.write({ db in
                try db.drop(index: "name_index")
            })
插入
try cursor.write({ (db) in
    let exists = try db.tableExists("user")
    if exists {
        try db.execute(
            sql: """
                INSERT INTO user(name, age, address)
                VALUES(?,?,?)
            """,
            arguments: ["kevin",12,"address"])
    }
})

statement 方式插入


		try cursor.write({ (db) in
                let exists = try db.tableExists("user")
                if exists {
                    let statement = try db.makeUpdateStatement(sql: """
                        INSERT INTO user(name, age, address)
                        VALUES(?,?,?)
                        """)
                    try statement.execute(arguments: ["kevin",12,"address"])
                    try statement.execute(arguments: ["kevin",12,"address"])
                    try statement.execute(arguments: ["kevin",12,"address"])
                }
            })
更新
			try cursor.write({ (db) in
                let exists = try db.tableExists("user")
                
                if exists {
                    try db.execute(sql: """
                        UPDATE user SET name = ?, age = ?, address = ?
                        WHERE name = ?
                        """, arguments: ["kevin5",12,"address", "kevin"])
                    
                    try db.execute(sql: """
                        UPDATE user SET name = :name, age = :age, address = :address
                        WHERE name = :name2
                        """, arguments: ["name": "kevin5", "age": 12, "address": "address", "name2": "kevin"])
                    
                }
                
            })

statement 方式

		try cursor.write({ (db) in
                let exists = try db.tableExists("user2")
                
                if exists {
                    let statement = try db.makeUpdateStatement(sql: """
                        UPDATE user SET name = ?, age = ?, address = ?
                        WHERE name = ?
                        """)
                    try statement.execute(arguments: ["kevin5",12,"address", "kevin"])
                }
                
查询

查询是需要使用class Row 进行查询, 也可以使用数据库存储数据类型进行查询.(DatabaseValueConvertible)

			try cursor.read({ db in
                let exists = try db.tableExists("user")
                
                if exists {
                    let statement = try db.makeSelectStatement(sql: """
                        select * from user
                        """)
                    let res = try Row.fetchAll(statement)
                    print(res)
                    
                    
                    let res2 = try Row.fetchAll(db, sql: "SELECT * FROM user")
                    if res2.isEmpty == false {
                        let r = res2[0]
                        print(r)
                        print(r["name"] as String)
                    }
                    
                    
                    let res3 = try String.fetchAll(db, sql: "select name from user")
                    print(res3)
                    
                    let res4 = try Row.fetchCursor(db, sql: "SELECT * FROM user")
                    while let r = try res4.next() {
                        debugPrint(r["id"] as Int)
                        debugPrint(r[Column("name")] as String)
                    }
                }
            })

直接过去某个数据

			let name: String? = try cursor.read { (db) -> String? in
                return try String.fetchOne(db, sql: "select name from user where id = 1")
            }
删除
		guard let cursor = dbPool else {
            return
        }
        
        do {
            try cursor.write({ (db) in
                let exists = try db.tableExists("user")
                if exists {
                    try db.execute(
                        sql: """
                        DELETE FROM user
                        WHERE id > 30
                        """)
                }
            })
        } catch let error {
            debugPrint(error)
        }

使用 API 操作

创建存储模型

基础部分, 建议使用 Codable 协议

struct UserEntity: Codable  {
    var id: Int?
    var name: String?
    var age: Int?
    var address: String?
}

使用 ColumnExpression 声明列名表示, 在 CURD 中直接使用 Columns.id/.name/.age/.address 进行操作数据

extension UserEntity {    
    enum Columns: String, ColumnExpression {
        case id, name, age, address
    }
}

使用 TableRecord 协议, 告知操作数据表

extension UserEntity: TableRecord {
//  数据表名字 如果不自定义 将使用默认的表名, 默认为小写开头驼峰命名 例如 UserEntity -> userEntity
    static var databaseTableName: String {
        return "user"
    }
    // 查询字段, 默认使用 *  ,  复制后将使用 id, name, age, address 
    // static var databaseSelection: [SQLSelectable] = [Column("id"), Column("name"), Column("age"), Column("address")]
    // 同上 声明列名表示的方式
    static var databaseSelection: [SQLSelectable] = [Columns.id, Columns.name, Columns.age, Columns.address]
}

FetchableRecord 进行查询操作, 使用了Codable可以不实现init(row: Row)

// fetch
extension UserEntity: FetchableRecord {
    // 未使用 Codable = Decodable & Encodable 协议的 需要实现init(row: Row)
    init(row: Row) {
        id = row["id"]
        name = row["name"]
        age = row[Columns.age]
        address = row[Columns.address]
    }

}

使用PersistableRecord / MutablePersistableRecord插入更新保存数据, 存储模型是Class使用PersistableRecord, 存储模型是struct使用MutablePersistableRecord. 两者区别在于 MutablePersistableRecord save() insert()mutating.

// insert
extension UserEntity: MutablePersistableRecord {
    func encode(to container: inout PersistenceContainer) {
        container["id"] = id
        container[Columns.name] = name
        container[Columns.address] = address
        container[Columns.age] = age
    }
    mutating func didInsert(with rowID: Int64, for column: String?) {
        id = Int(rowID)
    }
    
}
创建表
		try db.create(table: databaseTableName, temporary: false, ifNotExists: true, body: { (t) in
            t.autoIncrementedPrimaryKey("id")
            t.column("name", .text)
            t.column("age", .integer)
            t.column("address", .text)
        })
插入
			try cursor.write({ (db) -> Void in
                var user = UserEntity(id: nil, name: "kk", age: 22, address: "kk.ads")
                try user.insert(db)
            })
查询
			guard let user = try cursor.read({ (db) -> UserEntity? in
                return try UserEntity.fetchOne(db, sql: "select * from user where id == 20")
            }) else {
                return
            }
			guard let user2 = try cursor.read({ (db) -> UserEntity? in
                //                return try UserEntity.filter(key: 30).fetchOne(db)
                return try UserEntity.fetchOne(db, key: 30)
                //                return try UserEntity.fetchOne(db)
            }) else {
                return
            }
更新
			guard var kk = try cursor.read({ (db) -> UserEntity? in
                return try UserEntity.filter(sql: "name == 'kk'").fetchOne(db)
            }) else {
                debugPrint("fetch kk error")
                return
            }
            try cursor.write({ (db) -> Void in
                try kk.updateChanges(db, with: { (u) in
                    u.address = "k.kkkkkkk"
                })
//                try kk.updateChanges(db) {
//                    $0.address = "k.kkkkkkk"
//                }
            })
			var newkk = kk
            newkk.address = "k.kk.kk"

            try cursor.write({ (db) -> Void in
                try newkk.updateChanges(db, from: kk)
            })
删除
            guard let kk = try cursor.read({ (db) -> UserEntity? in
                return try UserEntity.filter(sql: "name == 'kk'").fetchOne(db)
            }) else {
                debugPrint("fetch kk error")
                return
            }
            try cursor.write({ (db) -> Void in
                try kk.delete(db)
            })
        }catch {
            debugPrint("delete error")
        }

迁移

GRDB通过注册标识(可写成版本号)进行数据库迁移操作.

创建迁移对象
        var migrator = DatabaseMigrator()
查询应用迁移
		do {
            let res = try migrator.appliedMigrations(in: dbPool!)
            print(res.contains("v1"))
            print(res.contains("v2"))
        } catch let error {
            debugPrint(error)
        }
注册
		migrator.registerMigration("v1") { (db) in
            try db.create(table: "user_entity", body: { (t) in
                t.autoIncrementedPrimaryKey("id")
                t.column("name", .text)
                t.column("address", .text)
                t.column("age", .integer)
            })
        }
        
        migrator.registerMigration("v2") { (db) in
            try db.alter(table: "user_entity", body: { (t) in
                t.add(column: "time", .date).notNull().defaults(to: Date())
            })
        }
执行
		do {
            try migrator.migrate(dbPool!)
//            try migrator.migrate(dbPool!, upTo: "v2")
        }catch {
            print("error migrator")
        }

仅为个人学习记录, 详细操作, 请移步官方文档.

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: sqlite-jdbc-3.25.1.jar 是一个用于连接和操作 SQLite 数据库的 Java 驱动程序。它提供了在 Java 程序中对 SQLite 数据库进行读取和写入的功能。 SQLite 是一个轻量级的嵌入式数据库引擎,被广泛应用于移动设备和嵌入式系统中。而 sqlite-jdbc-3.25.1.jar 则是 SQLite 数据库的 Java 接口,它允许开发者使用 Java 语言来访问和操作 SQLite 数据库。该驱动程序允许在 Java 应用程序中使用 SQL 语句对 SQLite 数据库进行增、删、改、查等操作。 使用 sqlite-jdbc-3.25.1.jar 进行 SQLite 数据库操作非常简单。开发者只需在 Java 项目中引入该驱动程序的 Jar 文件,并使用 Java 代码进行连接和操作数据库即可。通过创建 Connection 对象,开发者可以连接到 SQLite 数据库。然后,可以使用该对象创建 Statement 对象,并通过执行 SQL 查询和更新语句来操作数据库中的数据。最后,需确保在使用完毕后,关闭相关的连接和资源。 除了提供基本的数据库连接和操作功能外,sqlite-jdbc-3.25.1.jar 还支持事务管理、预编译 SQL 语句、批量处理等高级功能,使得 SQLite 数据库在 Java 程序中的使用更加灵活和高效。 总而言之,sqlite-jdbc-3.25.1.jar 是一个用于连接和操作 SQLite 数据库的 Java 驱动程序。它方便了开发者在 Java 程序中使用 SQL 语句对 SQLite 数据库进行操作,为开发者提供了一个简单、高效的访问 SQLite 数据库的接口。 ### 回答2: sqlite-jdbc-3.25.1.jar是一个Java编程语言的SQLite数据库驱动程序。SQLite是一种轻量级的关系型数据库管理系统,具有快速、可靠和易于集成的特点。它是一个嵌入式数据库,不需要独立的服务器进程,可以直接在应用程序中使用sqlite-jdbc-3.25.1.jar是SQLite官方提供的Java接口实现。它提供了对SQLite数据库的连接、查询、插入、更新和删除等操作的支持。通过引入该jar包,我们可以在Java应用程序中使用SQLite数据库,进行数据的持久化存储和访问。 使用sqlite-jdbc-3.25.1.jar可以简化与SQLite数据库的交互过程。我们只需在Java程序中引入该库,并配置相应的连接参数,即可创建和管理SQLite数据库连接对象。然后,我们可以使用SQL语句来执行数据库操作,例如查询表中的数据、插入新的记录、更新已有记录等。 sqlite-jdbc-3.25.1.jar还提供了一些其他的功能和特性,例如批量操作、事务处理、预编译语句、连接池管理等,可以进一步优化数据库操作的性能和效率。 总之,sqlite-jdbc-3.25.1.jar是一个能够在Java应用程序中与SQLite数据库进行交互的驱动程序。通过使用它,我们可以更方便地使用SQLite作为数据存储和管理的解决方案,实现数据持久化和访问的需求。 ### 回答3: sqlite-jdbc-3.25.1.jar 是SQLite数据库的Java驱动程序。它是用于在Java应用程序中与SQLite数据库进行交互的关键库文件。SQLite是一个轻量级的嵌入式关系型数据库,适用于移动设备和小型应用。而sqlite-jdbc-3.25.1.jar允许Java开发人员通过提供一个简单的API来连接和操作SQLite数据库。 sqlite-jdbc-3.25.1.jar提供了一系列的类和方法,使开发人员可以轻松地创建、查询、更新和删除数据库中的数据。它支持执行SQL语句、预编译语句、事务管理等数据库操作。从连接数据库、执行SQL语句到关闭数据库连接,sqlite-jdbc-3.25.1.jar提供了一套完整的功能来简化与SQLite数据库的交互。 使用sqlite-jdbc-3.25.1.jar可以带来很多好处。首先,它提供了一个简单而易于使用的API,使得在Java应用程序中使用SQLite数据库变得更加方便。其次,它具有良好的性能和可靠性,能够处理大量数据和高并发访问。另外,sqlite-jdbc-3.25.1.jar是开源的,意味着开发人员可以根据自己的需求进行定制和扩展。最重要的是,由于SQLite是一个嵌入式数据库,所以在使用sqlite-jdbc-3.25.1.jar时不需要额外安装和配置数据库服务器,这使得应用程序的部署更加简单和便捷。 总而言之,sqlite-jdbc-3.25.1.jar是一个重要的Java库文件,它使得在Java应用程序中使用SQLite数据库变得更加便捷和高效。它具有简单易用的API、良好的性能和可靠性,适用于各种规模的应用程序。无论是在移动设备还是小型应用中,sqlite-jdbc-3.25.1.jar都是首选的数据库驱动程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值