Swift 中使用 SQLite——批量更新(事務處理)

本文是Swift 中使用 SQLite系列的收官之作,介紹一下在數據庫中的批量更新。

事務

  • 在準備做大規模數據操作前,首先開啓一個事務,保存操作前的數據庫的狀態
  • 開始數據操作
  • 如果數據操作成功,提交事務,讓數據庫更新到數據操作後的狀態
  • 如果數據操作失敗,回滾事務,讓數據庫還原到操作前的狀態

準備事務代碼

// MARK: - 事務處理
/// 開啓事務
func beginTransaction() {
    sqlite3_exec(db, "BEGIN TRANSACTION;", nil, nil, nil)
}

/// 提交事務
func commitTransaction() {
    sqlite3_exec(db, "COMMIT TRANSACTION;", nil, nil, nil)
}

/// 回滾事務
func rollbackTransaction() {
    sqlite3_exec(db, "ROLLBACK TRANSACTION;", nil, nil, nil)
}

用事務插入大量數據

  • 不使用事務插入數據
/// 不使用事務插入多條記錄 - 測試記錄 5s
private func manyPerson1() {
    print("start")
    let start = CACurrentMediaTime()

    for i in 0..<10000 {
        Person(dict: ["name": "zhang - \(i)", "age": 18, "height": 1.7]).insertPerson()
    }
    print("over \(CACurrentMediaTime() - start)")
}
  • 使用事務插入數據
/// 使用事務插入多條數據 - 測試記錄 0.4s
private func manyPerson2() {
    print("start")
    let start = CACurrentMediaTime()

    SQLiteManager.sharedManager.execSQL("BEGIN TRANSACTION;")

    for i in 0..<10000 {
        Person(dict: ["name": "zhang - \(i)", "age": 18, "height": 1.7]).insertPerson()
    }

    SQLiteManager.sharedManager.execSQL("COMMIT TRANSACTION;")

    print("over \(CACurrentMediaTime() - start)")
}

原因:在 SQLite 中,如果不主動開啓事務,每個數據更新操作 (INSERT / UPDATE / DELETE) 都會默認開啓一個事務,數據更新結束後自動提交事務

  • 模擬失敗
/// 模擬失敗
private func manyPerson3() {
    print("start")
    let start = CACurrentMediaTime()

    SQLiteManager.sharedManager.execSQL("BEGIN TRANSACTION;")

    for i in 0..<10000 {
        Person(dict: ["name": "zhang - \(i)", "age": 18, "height": 1.7]).insertPerson()

        if i == 1000 {
            SQLiteManager.sharedManager.execSQL("ROLLBACK TRANSACTION;")
            // 注意:一定要使用 break 退出循環
            break;
        }
    }

    SQLiteManager.sharedManager.execSQL("COMMIT TRANSACTION;")

    print("over \(CACurrentMediaTime() - start)")
}
  • 標準寫法
/// 標準寫法
private func manyPerson4() {
    print("start")
    let start = CACurrentMediaTime()

    SQLiteManager.sharedManager.execSQL("BEGIN TRANSACTION;")

    for i in 0..<10000 {
        if !Person(dict: ["name": "zhang - \(i)", "age": 18, "height": 1.7]).insertPerson() {
            SQLiteManager.sharedManager.execSQL("ROLLBACK TRANSACTION;")
            break;
        }
    }

    SQLiteManager.sharedManager.execSQL("COMMIT TRANSACTION;")

    print("over \(CACurrentMediaTime() - start)")
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章