SQLite崩潰處理
關于SQLite
SQLite 支持如下三種線程模型
- 單線程模型 這種模型下,所有互斥鎖都被禁用,同一時間只能由一個線程訪問。
- 多線程模型 這種模型下,一個連接在同一時間內(nèi)只有一個線程使用就是安全的。
- 串行模型 開啟所有鎖,可以隨意訪問。
設置線程模型
SQLite 可以通過以下三種方式進行線程模型的設置,在實際應用中選擇任一一項都可以。
- 編譯期設定 通過 SQLITE_THREADSAFE 這個參數(shù)進行編譯器的設定來選擇線程模型
- 初始化設定 通過調(diào)用 sqlite3_config() 可以在 SQLite 初始化時進行設定
- 運行時設定 通過調(diào)用 sqlite3_open_v2() 接口指定數(shù)據(jù)庫連接的數(shù)據(jù)庫模型
SQLite 并發(fā)和事務
事務
事務是 SQLite 的核心概念。對數(shù)據(jù)庫的操作 (絕大部分) 會被打包成一個事務進行提交,需要注意的是,這里的打包成事務是自動開啟的。舉例而言,如果簡單在一個 for 循環(huán)語句里向數(shù)據(jù)庫中插入 10 條數(shù)據(jù),意味著將自動生成 10 個事務。但需要注意的是事務是非常耗時的,一般而言, SQLite 每秒能夠輕松支持 50000 條的數(shù)據(jù)插入,但是每秒僅能夠支持幾十個事務。一般而言,事務速度受限于磁盤速度。所以在批量插入時需要考慮禁用自動提交,將其用 BEGIN ... COMMIT 打包成一個事務。
回滾模式和 WAL
Write-Ahead Log (常簡寫為 WAL)
為了保證寫入正確,SQLite 在使用事務進行數(shù)據(jù)庫改寫時將拷貝當前數(shù)據(jù)庫文件的備份,即 rollback journal,當事務失敗或者發(fā)生意外需要回滾時則將備份文件內(nèi)容還原到數(shù)據(jù)庫中,并同時刪除該日志。這是默認的 DELETE 模式。
而后 SQLite 也引入了 WAL 模式,即 Write-Ahead Log。在這種模式下,所有的修改會寫入一個單獨的 WAL 文件內(nèi)。這種模式下,寫操作甚至可以不去操作數(shù)據(jù)庫,這使得所有的讀操作可以在 "寫的同時" 直接對數(shù)據(jù)庫文件進行操作,得到更好的并發(fā)性能。
SQLite開啟wal代碼
SQLiteDatabase dataBase = DataBaseHelper.getWritableDatabase()
SQLiteDatabase dataBase.enableWriteAheadLogging();
鎖和并發(fā)
SQLite 通過五種鎖狀態(tài)來完成事務。
- UNLOCKED ,無鎖狀態(tài)。數(shù)據(jù)庫文件沒有被加鎖。
- SHARED 共享狀態(tài)。數(shù)據(jù)庫文件被加了共享鎖??梢远嗑€程執(zhí)行讀操作,但不能進行寫操作。
- RESERVED 保留狀態(tài)。數(shù)據(jù)庫文件被加保留鎖。表示數(shù)據(jù)庫將要進行寫操作。
- PENDING 未決狀態(tài)。表示即將寫入數(shù)據(jù)庫,正在等待其他讀線程釋放 SHARED 鎖。一旦某個線程持有 PENDING 鎖,其他線程就不能獲取 SHARED 鎖。這樣一來,只要等所有讀線程完成,釋放 SHARED 鎖后,它就可以進入 EXCLUSIVE 狀態(tài)了。
EXCLUSIVE 獨占鎖。表示它可以寫入數(shù)據(jù)庫了。進入這個狀態(tài)后,其他任何線程都不能訪問數(shù)據(jù)庫文件。因此為了并發(fā)性,它的持有時間越短越好。
一個線程只有擁有低級別鎖時才能夠獲得更高一級的鎖
要保證數(shù)據(jù)庫使用的安全,一般可以采用如下幾種模式
SQLite 采用單線程模型,用專門的線程/隊列(同時只能有一個任務執(zhí)行訪問) 進行訪問
SQLite 采用多線程模型,每個線程都使用各自的數(shù)據(jù)庫連接 (即 sqlite3 *)
SQLite 采用串行模型,所有線程都公用同一個數(shù)據(jù)庫連接。
因為寫操作的并發(fā)性并不好,當多線程進行訪問時實際上仍舊需要互相等待,而讀操作所需要的 SHARED 鎖是可以共享的,所以為了保證最高的并發(fā)性,推薦
使用多線程模式
使用 WAL 模式
單線程寫,多線程讀 (各線程都持有自己對應的數(shù)據(jù)庫連接)
避免長時間事務
緩存 sqlite3_prepare 編譯結(jié)果
多語句通過 BEGIN 和 COMMIT 做顯示事務,減少多次的自動事務消耗
SQLite錯誤號
1 #define SQLITE_OK 0 /* 成功 | Successful result */
2 /* 錯誤碼開始 */
3 #define SQLITE_ERROR 1 /* SQL錯誤 或 丟失數(shù)據(jù)庫 | SQL error or missing database */
4 #define SQLITE_INTERNAL 2 /* SQLite 內(nèi)部邏輯錯誤 | Internal logic error in SQLite */
5 #define SQLITE_PERM 3 /* 拒絕訪問 | Access permission denied */
6 #define SQLITE_ABORT 4 /* 回調(diào)函數(shù)請求取消操作 | Callback routine requested an abort */
7 #define SQLITE_BUSY 5 /* 數(shù)據(jù)庫文件被鎖定 | The database file is locked */
8 #define SQLITE_LOCKED 6 /* 數(shù)據(jù)庫中的一個表被鎖定 | A table in the database is locked */
9 #define SQLITE_NOMEM 7 /* 某次 malloc() 函數(shù)調(diào)用失敗 | A malloc() failed */
10 #define SQLITE_READONLY 8 /* 嘗試寫入一個只讀數(shù)據(jù)庫 | Attempt to write a readonly database */
11 #define SQLITE_INTERRUPT 9 /* 操作被 sqlite3_interupt() 函數(shù)中斷 | Operation terminated by sqlite3_interrupt() */
12 #define SQLITE_IOERR 10 /* 發(fā)生某些磁盤 I/O 錯誤 | Some kind of disk I/O error occurred */
13 #define SQLITE_CORRUPT 11 /* 數(shù)據(jù)庫磁盤映像不正確 | The database disk image is malformed */
14 #define SQLITE_NOTFOUND 12 /* sqlite3_file_control() 中出現(xiàn)未知操作數(shù) | Unknown opcode in sqlite3_file_control() */
15 #define SQLITE_FULL 13 /* 因為數(shù)據(jù)庫滿導致插入失敗 | Insertion failed because database is full */
16 #define SQLITE_CANTOPEN 14 /* 無法打開數(shù)據(jù)庫文件 | Unable to open the database file */
17 #define SQLITE_PROTOCOL 15 /* 數(shù)據(jù)庫鎖定協(xié)議錯誤 | Database lock protocol error */
18 #define SQLITE_EMPTY 16 /* 數(shù)據(jù)庫為空 | Database is empty */
19 #define SQLITE_SCHEMA 17 /* 數(shù)據(jù)結(jié)構(gòu)發(fā)生改變 | The database schema changed */
20 #define SQLITE_TOOBIG 18 /* 字符串或二進制數(shù)據(jù)超過大小限制 | String or BLOB exceeds size limit */
21 #define SQLITE_CONSTRAINT 19 /* 由于約束違例而取消 | Abort due to constraint violation */
22 #define SQLITE_MISMATCH 20 /* 數(shù)據(jù)類型不匹配 | Data type mismatch */
23 #define SQLITE_MISUSE 21 /* 不正確的庫使用 | Library used incorrectly */
24 #define SQLITE_NOLFS 22 /* 使用了操作系統(tǒng)不支持的功能 | Uses OS features not supported on host */
25 #define SQLITE_AUTH 23 /* 授權(quán)失敗 | Authorization denied */
26 #define SQLITE_FORMAT 24 /* 附加數(shù)據(jù)庫格式錯誤 | Auxiliary database format error */
27 #define SQLITE_RANGE 25 /* 傳遞給sqlite3_bind()的第二個參數(shù)超出范圍 | 2nd parameter to sqlite3_bind out of range */
28 #define SQLITE_NOTADB 26 /* 被打開的文件不是一個數(shù)據(jù)庫文件 | File opened that is not a database file */
29 #define SQLITE_ROW 100 /* sqlite3_step() 已經(jīng)產(chǎn)生一個行結(jié)果 | sqlite3_step() has another row ready */
30 #define SQLITE_DONE 101 /* sqlite3_step() 完成執(zhí)行操作 | sqlite3_step() has finished executing */
Android版本與SQLite版本對應關系
| Android | SQLite |
|---|---|
| API 27 | 3.19 |
| API 26 | 3.18 |
| API 24 | 3.9 |
| API 21 | 3.8 |
| API 11 | 3.7 |
| API 8 | 3.6 |
| API 3 | 3.5 |
| API 1 | 3.4 |