FMDB Swift版使用


FMDBは、OC言語を使用してオリジナルのSQLiteをパッケージ化したライブラリで、オリジナルのSQLite文を使用して操作することができ、マルチスレッドをサポートしてスレッドの安全性を保証します.
一:使用手順のインストール
SPM: https://github.com/ccgus/fmdb

使用時にパッケージをインポートすればいいです.例えばimport FMDB二:DBHelperクラスの作成
アクセス用に単一のツールクラスを作成します.
import Foundation
import FMDB
 
class SQLiteManager: NSObject {
     
     
    // Create Single instance.
    private static let manger: SQLiteManager = SQLiteManager()
    class func getInstance() -> SQLiteManager {
     
        return manger
    }
     
    // Database's name.
    private let dbName = "table_basic.db"
     
    // URL
    lazy var dbURL: URL = {
     
        let fileURL = try! FileManager.default
            .url(for: .applicationSupportDirectory, in: .userDomainMask,
                 appropriateFor: nil, create: true)
            .appendingPathComponent(dbName)
        print("------>Database URL:", fileURL)
        return fileURL
    }()
     
    // FMDatabase Object.
    lazy var db: FMDatabase = {
     
        let database = FMDatabase(url: dbURL)
        return database
    }()
     
    // FMDatabaseQueue Object.
    lazy var dbQueue: FMDatabaseQueue? = {
     
        let databaseQueue = FMDatabaseQueue(url: dbURL)
        return databaseQueue
    }()
}

helperクラスにはデータテーブル名(sqliteはユーザにとってデータベースがなく、データテーブルのみ)が格納されており、使用するたびにインスタンスオブジェクトを取得して追加削除して検索すればよい.
三:添削改ざんタイプ操作
1.初期化
    @IBAction func initListener(_ sender: Any) {
     
        let db = SQLiteManager.getInstance().db
        if db.open() {
     
            print("DATABASE INIT SUCCEED.")
        } else {
     
            print("ERROR AT: \(db.lastError())")
        }
    }

2.テーブルの作成
追加削除・変更は、Javaの前処理方式を使用して実行できます.たとえば、SQL文はスペルが完了しています.SQL文の所定のパラメータをに置き換えるだけですか?withArgumentsIn: []で変数を対応付けて入力すればよい.なお、FMDBではクエリのみがexecuteQuery()であり、残りはexecuteUpdate()である.
    @IBAction func createListener(_ sender: Any) {
     
        let sql = "create table if not exists table_basic (id integer primary key autoincrement, name text);"
        let db = SQLiteManager.getInstance().db
        if db.open(){
     
            try! db.executeUpdate(sql, withArgumentsIn: [])
        } else{
     
            print("ERROR AT \(db.lastError())")
        }
        db.close()
    }

3.増加
    @IBAction func addListener(_ sender: Any) {
     
        let sql = "insert into table_basic (id, name) values(?,?);"
        let db = SQLiteManager.getInstance().db
        if db.open(){
     
            try! db.executeUpdate(sql, withArgumentsIn: [2007001, "jack"])
        } else{
     
            print("ERROR AT \(db.lastError())")
        }
        db.close()
    }

4.削除
    @IBAction func delListener(_ sender: Any) {
     
        let sql = "delete from table_basic where id = 2007001;"
        let db = SQLiteManager.getInstance().db
        if db.open(){
     
            try! db.executeUpdate(sql, withArgumentsIn: [])
        } else{
     
            print("ERROR AT \(db.lastError())")
        }
        db.close()
    }

もちろん、以下のように前処理することもできます.
    @IBAction func delListener(_ sender: Any) {
     
        let sql = "delete from table_basic where id = ?;"
        let db = SQLiteManager.getInstance().db
        if db.open(){
     
            try! db.executeUpdate(sql, withArgumentsIn: [2007001])
        } else{
     
            print("ERROR AT \(db.lastError())")
        }
        db.close()
    }

5.変更
    @IBAction func updateListener(_ sender: Any) {
     
        let sql = "update table_basic set name = "" where id = ?;"
        let db = SQLiteManager.getInstance().db
        if db.open(){
     
            try! db.executeUpdate(sql, withArgumentsIn: ["rose", 2007001])
        } else{
     
            print("ERROR AT \(db.lastError())")
        }
        db.close()
    }

6.調査
ここでのクエリはJDBCのResultSetに類似しており、FMDBにもFMDBResultSetに類似したクエリ結果セットオブジェクトが存在する.なお、Stringタイプのデータは一般的にoptionalタイプであり、パケットを解くことを忘れないでください.
    @IBAction func searchListener(_ sender: Any) {
     
        let sql = "select * from table_basic;"
        let db = SQLiteManager.getInstance().db
        if db.open() {
     
            if let resultSet = db.executeQuery(sql, withArgumentsIn: []) {
     
                while resultSet.next() {
     
                    print("DATA IS \(resultSet.int(forColumn: "id"))")
                    print("DATA IS \(resultSet.string(forColumn: "name")!)")
                }
            }
        } else {
     
            print("ERROR AT \(db.lastError())")
        }
        db.close()
    }

四:マルチデータ型ストレージ
SQLiteは、一般的なdate、varcharなどのタイプのデータだけでなく、バイナリタイプのデータもblobとして格納できます.次に、画像をデータベースにバイナリタイプで格納し、読み出してビューに表示します.まずテーブルを作成する手順は、次のとおりです.
    @IBAction func createListener(_ sender: Any) {
     
        let sql = "create table if not exists table_bin (id integer primary key autoincrement, content_data blob);"
        let db = SQLiteManager.getInstance().db
        if db.open(){
     
            try! db.executeUpdate(sql, withArgumentsIn: [])
        } else{
     
            print("ERROR AT \(db.lastError())")
        }
        db.close()
    }

ここにcontentという名前が作成されていることがわかります.Dataのblobタイプのフィールドは、残りは特にありません.次はストレージの操作です.ここでは、前処理文でピクチャを格納する必要がある(ピクチャはDataタイプに変換する必要がある).
@IBAction func alterListener(_ sender: Any) {
     
        let sql = "insert into table_bin (id, content_data) values(?,?);"
        let db = SQLiteManager.getInstance().db
        if db.open() {
     
            // Convert UIImage object into Data object.
            let image = UIImage(named: "testimg")
            let data = image?.pngData()
            // Store into preprocessing statement.
            try! db.executeUpdate(sql, withArgumentsIn: [2007003, data])
        } else{
     
            print("ERROR AT \(db.lastError())")
        }
        db.close()
    }

次は読み込みです.読み込み時にデータの解包に注意すればいいです.操作は次のとおりです.
    @IBAction func searchListener(_ sender: Any) {
     
        let sql = "select * from table_bin;"
        let db = SQLiteManager.getInstance().db
        if db.open() {
     
            if let resultSet = db.executeQuery(sql, withArgumentsIn: []) {
     
                while resultSet.next() {
     
                    let imageData = resultSet.data(forColumn: "content_data")! as? Data
                    self.imageView.image = UIImage(data: imageData!)
                }
            }
        } else {
     
            print("ERROR AT \(db.lastError())")
        }
        
        db.close()
    }

五:事物類操作
FMDBは同様に物事タイプの操作をサポートする.物事には4つの特性(ACID)がある.ここでは,物事キューが一括操作を行い,成功と失敗を示す.
    @IBAction func searchListener(_ sender: Any) {
     
        if let queue = SQLiteManager.getInstance().dbQueue {
     
            queue.inTransaction {
      db, rollback in
                do {
     
                    for i in 0..<10 {
     
                        try db.executeUpdate("insert into table_basic (id, name) values (?,?);",
                                             values: [i, "jack"])
                    }
                } catch {
     
                    print("ERROR AND ROLLBACK.")
                    rollback.pointee = true
                }
            }
        }
    }

通常、上記の内容はすべて正常に挿入されます.次は例外です.
   @IBAction func searchListener(_ sender: Any) {
     
       if let queue = SQLiteManager.getInstance().dbQueue {
     
           queue.inTransaction {
      db, rollback in
               do {
     
                   for i in 0..<10 {
     
                       if i == 5 {
     
                           try db.executeUpdate("insert into table_error (id, name) values (?,?);",
                                                values: [i, "jack"])
                       }
                       try db.executeUpdate("insert into table_basic (id, name) values (?,?);",
                                            values: [i, "jack"])
                   }
               } catch {
     
                   print("ERROR AND ROLLBACK.")
                   rollback.pointee = true
               }
           }
       }
   }

ロールバックが設定されているため、5回目に実行される文は存在しないデータテーブルであり、通常は前の4組の挿入に成功したデータも削除され、ロールバックです.
六:Modelに合わせる
七:ファジイクエリ
SQLiteはlike、glob文をサポートします.likeは大文字と小文字を区別せず、globは大文字と小文字を区別します.次に、両者の例を示します.
    @IBAction func searchListener(_ sender: Any) {
     
        let sql = "select * from table_basic where name like '%j%';"
        let db = SQLiteManager.getInstance().db
        if db.open() {
     
            if let resultSet = db.executeQuery(sql, withArgumentsIn: []) {
     
                while resultSet.next() {
     
                    print("DATA IS \(resultSet.int(forColumn: "id"))")
                    print("DATA IS \(resultSet.string(forColumn: "name")!)")
                }
            }
        } else {
     
            print("ERROR AT \(db.lastError())")
        }
        db.close()
    }

globは上の文とは異なります.
let sql = "select * from table_basic where name glob '*j*';"

八:グループ化
let sql = "select name from table_basic group by name"

nameを重複するパケット・クエリーから削除すると、結果として異なるname値は対応する唯一のロー・レコードのみになります.もちろん、この文は具体的なビジネス・ロジックを参照してください.
九:並べ替え
let sql = "select * from table_basic order by id asc"

idに対して昇順を条件とするクエリーを行う
十:トリガー
トリガの作成にはexecuteUpdate()文が使用されます.あるテーブルにユーザーのアカウント、パスワード、前回のパスワードが記録されていると仮定します.最後のパスワードの役割は、ユーザーが変更する前に最後のパスワードと重複することを防止することです.では、その創表文は次のようになります.
let sql = "create table if not exists test_trigger(id integer primary key,password varchar(20),pass_password varchar(20))"

トリガ文は次のとおりです.
    @IBAction func triggerListener(_ sender: Any) {
     
        let sql = "create trigger record_password before update on test_trigger begin insert into test_trigger(pass_password) values(old.password); end"
        let db = SQLiteManager.shareManger().db
        if db.open(){
     
            try! db.executeUpdate(sql, withArgumentsIn: [])
        } else{
     
            print("ERROR AT \(db.lastError())")
        }
        db.close()
    }

なお、トリガ文の外部条件をfor earch rowにしないでください.ここでiosのsqliteではfor each rowがサポートされていないわけではありませんが、この条件はオプションです.ほとんどの場合、トリガ文は行操作、すなわち外部条件がfor each rowであり、内部がupdateであるなどの場合、ループ参照をもたらすためである.
十一:索引
インデックスは比較的簡単で、同じexecuteUpdate()で、文は以下の通りです.
let sql = "create index my_index on table_basic(id);"