【问题标题】:Inserting more than 250 records to SQLite at a time一次向 SQLite 插入超过 250 条记录
【发布时间】:2018-01-29 13:16:14
【问题描述】:

我需要在现有的SQLite 数据库中插入超过 1,000 条记录。为此,我有一个包含一些静态函数的类,如下所示。

class Application {
    static func openDatabase(path: String) -> OpaquePointer? {
        var db: OpaquePointer? = nil
        if sqlite3_open(path, &db) == SQLITE_OK {
            return db
        } else {
            return nil
        }
    }

    static func createTable(path: String) {
        let open = openDatabase(path: path)
        var createTableStatement: OpaquePointer? = nil
        let sqlCreate = "CREATE TABLE IF NOT EXISTS data (ID INTEGER PRIMARY KEY AUTOINCREMENT, year text, month text, day text, x1 text, x2 text, x3 text)"
        if sqlite3_prepare_v2(open, sqlCreate, -1, &createTableStatement, nil) == SQLITE_OK {
            if sqlite3_step(createTableStatement) == SQLITE_DONE {
                print("Table created.")
            } else {
                print("Table could not be created.")
            }
        } else {
            print("CREATE TABLE statement could not be prepared.")
        }
        sqlite3_finalize(createTableStatement)
    }

    static func insertRecord(path: String, year: String, month: String, day: String) {
        let open = openDatabase(path: path)
        var insertStatement: OpaquePointer? = nil
        let sqlInsert = "INSERT INTO data (year, month, day) VALUES (?, ?, ?)"
        if sqlite3_prepare_v2(open, sqlInsert, -1, &insertStatement, nil) == SQLITE_OK {
            let yearStr = year as NSString
            let monthStr = month as NSString
            let dayStr = day as NSString
            sqlite3_bind_text(insertStatement, 1, yearStr.utf8String, -1, nil)
            sqlite3_bind_text(insertStatement, 2, monthStr.utf8String, -1, nil)
            sqlite3_bind_text(insertStatement, 3, dayStr.utf8String, -1, nil)
            if sqlite3_step(insertStatement) == SQLITE_DONE {
                print("Successfully inserted row.")
            } else {
                print("Could not insert row.")
            }
        } else {
            print("INSERT statement could not be prepared.")
        }
        // 5
        sqlite3_finalize(insertStatement)
    }
}

然后我从AppDelegate 插入记录。如果我第二次运行它以便将记录插入数据库,如下所示,

class AppDelegate: UIResponder, UIApplicationDelegate {
    var appFile = String()

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        appFile = folderPath(s: 0, name: "Application")
        if !pathExists(path: appFile) {
            Application.createTable(path: appFile)
        } else {
            for i in 0..<10 {
                for j in 0..<12 {
                    for k in 0..<31 {
                        let yearStr = String(i + 2018)
                        let monthStr = String(j + 1)
                        let dayStr = String(k + 1)
                        Application.insertRecord(path: appFile, year: yearStr, month: monthStr, day: dayStr)
                    }
                }
            }
        }

        return true
    }
}

将 250 条记录插入数据库后,应用程序将崩溃。调试器说“NSInternalInconsistencyException”它崩溃了,我相信,因为应用程序一次打开 250 个文件。几年前,这不是问题,因为我们可以像这样关闭数据库

sqlite3_close(statement)

应用每次打开一个语句。现在,我们不能。那么我们可以做些什么来一次插入多条记录呢?谢谢。

【问题讨论】:

  • 错误信息暗示不允许打开到同一个数据库的多个连接,因为它违反了一致性。您需要访问相同的开放变量来执行数据库操作,而不是每次都创建。
  • @SubashKharel 不正确。您可以有多个连接。这里的问题是连接完成后它们都没有关闭。
  • 正是,当你不关闭前一个并新建并开始对数据库进行操作时,它更有可能发生。

标签: swift sqlite


【解决方案1】:

使用 SQLite 时,正确清理所有资源非常重要。您的主要问题是您在每次调用 insertRecord 时打开数据库,但您从不关闭数据库。这很糟糕。

对于sqlite_open 的每次成功调用都必须有对sqlite_close 的相应调用。

对于sqlite3_prepare_v2 的每次成功调用,都必须有对sqlite3_finalize 的相应调用以及对sqlite3_reset 的零次或多次调用。

你的方法应该是:

static func insertRecord(path: String, year: String, month: String, day: String) {
    if let open = openDatabase(path: path) {
        var insertStatement: OpaquePointer? = nil
        let sqlInsert = "INSERT INTO data (year, month, day) VALUES (?, ?, ?)"
        if sqlite3_prepare_v2(open, sqlInsert, -1, &insertStatement, nil) == SQLITE_OK {
            let yearStr = year as NSString
            let monthStr = month as NSString
            let dayStr = day as NSString
            sqlite3_bind_text(insertStatement, 1, yearStr.utf8String, -1, nil)
            sqlite3_bind_text(insertStatement, 2, monthStr.utf8String, -1, nil)
            sqlite3_bind_text(insertStatement, 3, dayStr.utf8String, -1, nil)
            if sqlite3_step(insertStatement) == SQLITE_DONE {
                print("Successfully inserted row.")
            } else {
                print("Could not insert row.")
            }
            sqlite3_finalize(insertStatement)
        } else {
            print("INSERT statement could not be prepared.")
        }

        sqlite3_close(open)
    } else {
        print("Database couldn't be open.")
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多