本文是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)")
}