Sqlite3 多線程訪問
Sqlite3 線程模式
sqlite3有三種線程模式,在編譯時開啟宏SQLITE_THREADSAFE=0/1/2來設置編譯支持,
sqlite3_config(SQLITE_CONFIG_SINGLETHREAD/SQLITE_CONFIG_SERIALIZED/SQLITE_CONFIG_MULTITHREAD/)運行時設置啟用
- 單線程
編譯時SQLITE_THREADSAFE=0 默認啟用
SQLITE_THREADSAFE=0/1/2
sqlite3_config(SQLITE_CONFIG_SINGLETHREAD)
- 多線程
編譯時SQLITE_THREADSAFE=2 默認啟用
SQLITE_THREADSAFE=1/2
sqlite3_config(SQLITE_CONFIG_MULTITHREAD)
- 串行
編譯時SQLITE_THREADSAFE=1 默認啟用
SQLITE_THREADSAFE=1/2
sqlite3_config(SQLITE_CONFIG_SERIALIZED)
Ubuntu 18.04 的Sqlite3 默認發行版 為串行模式
數據庫文件鎖狀態
SQLite數據庫文件有5種鎖的狀態。一個線程只有在擁有低級別的鎖的時候,才能獲取更高一級的鎖。SQLite就是靠這5種類型的鎖,巧妙地實現了讀寫線程的互斥。同時也可看出,寫操作必須進入EXCLUSIVE狀態,此時並發數被降到1,這也是SQLite被認為並發插入性能不好的原因。另外,read-uncommitted和WAL模式會影響這個鎖的機制。在這2種模式下,讀線程不會被寫線程阻塞,即使寫線程持有PENDING或EXCLUSIVE鎖。
- UNLOCKED:表示數據庫此時並未被讀寫。
- SHARED:表示數據庫可以被讀取。SHARED鎖可以同時被多個線程擁有。一旦某個線程持有SHARED鎖,就沒有任何線程可以進行寫操作。
- RESERVED:表示准備寫入數據庫。RESERVED鎖最多只能被一個線程擁有,此后它可以進入PENDING狀態。
- PENDING:表示即將寫入數據庫,正在等待其他讀線程釋放SHARED鎖。一旦某個線程持有PENDING鎖,其他線程就不能獲取SHARED鎖。這樣一來,只要等所有讀線程完成,釋放SHARED鎖后,它就可以進入EXCLUSIVE狀態了。
- EXCLUSIVE:表示它可以寫入數據庫了。進入這個狀態后,其他任何線程都不能訪問數據庫文件。因此為了並發性,它的持有時間越短越好。
多線程並發訪問
在默認串行模式下,多線程並發訪問同一數據庫,每個線程開啟一個連接,同時訪問時會返回錯誤 "database is locked".此時需要等待數據庫可寫/可讀時才能訪問.
根據數據庫文件鎖狀態,這不典型的讀寫鎖嗎,哈哈哈,來個測試
測試代碼如下
// read thread
void read_thread() {
Sqlite db;
for (int i = 0; i < rw_count_; ++i) {
if (use_lock_) {
rwlock::LockRead _(lock_);
db.test_read(i);
} else {
db.test_read(i);
}
}
}
// write thread
void write_thread() {
Sqlite db;
for (int i = 0; i < rw_count_; ++i) {
if (use_lock_) {
rwlock::LockWrite _(lock_);
db.test_write(i);
} else {
db.test_write(i);
}
}
}
測試結果
測試: 2個讀線程,2個寫線程,每個線程訪問數據庫10次
環境: WSL Ubuntu 18.04
# 不開啟讀寫鎖
Read Write Times: 10
Read Thread Count: 2
Write Thread Count: 2
Use Read Write Lock: 0
[139956121044800] db opened
[139956121044800] drop table user.
[139956121044800] create table user.
[139956121044800] insert data to user.
[139956121044800] db closed
[139956097255168] db opened
[139956005570304] db opened
[139956088801024] db opened
[139955997116160] db opened
[139956097255168] 0 db read OK.
[139956088801024] 0 db read OK.
[139956097255168] 1 db read OK.
[139956097255168] 2 db read error: database is locked
[139956088801024] 1 db read OK.
[139956097255168] 3 db read error: database is locked
[139956088801024] 2 db read error: database is locked
[139956097255168] 4 db read error: database is locked
[139956088801024] 3 db read error: database is locked
[139956097255168] 5 db read error: database is locked
[139956088801024] 4 db read error: database is locked
[139956097255168] 6 db read error: database is locked
[139956097255168] 7 db read error: database is locked
[139956088801024] 5 db read error: database is locked
[139956097255168] 8 db read error: database is locked
[139956088801024] 6 db read error: database is locked
[139956097255168] 9 db read error: database is locked
[139956088801024] 7 db read error: database is locked
[139956097255168] db closed
[139956088801024] 8 db read error: database is locked
[139956088801024] 9 db read error: database is locked
[139956088801024] db closed
[139955997116160] 0 db write error: database is locked
[139956005570304] 0 db write error: database is locked
[139956005570304] 1 db write error: database is locked
[139956005570304] 2 db write error: database is locked
[139956005570304] 3 db write error: database is locked
[139955997116160] 1 db write error: database is locked
[139955997116160] 2 db write error: database is locked
[139955997116160] 3 db write error: database is locked
[139956005570304] 4 db write error: database is locked
[139956005570304] 5 db write error: database is locked
[139956005570304] 6 db write error: database is locked
[139956005570304] 7 db write error: database is locked
[139956005570304] 8 db write error: database is locked
[139955997116160] 4 db write error: database is locked
[139955997116160] 5 db write error: database is locked
[139955997116160] 6 db write error: database is locked
[139955997116160] 7 db write error: database is locked
[139955997116160] 8 db write error: database is locked
[139955997116160] 9 db write error: database is locked
[139955997116160] db closed
[139956005570304] 9 db write OK.
[139956005570304] db closed
# 開啟讀寫鎖
Read Write Times: 10
Read Thread Count: 2
Write Thread Count: 2
Use Read Write Lock: 1
[140635615070016] db opened
[140635615070016] drop table user.
[140635615070016] create table user.
[140635615070016] insert data to user.
[140635615070016] db closed
[140635591280384] db opened
[140635565917952] db opened
[140635582826240] db opened
[140635574372096] db opened
[140635591280384] 0 db read OK.
[140635582826240] 0 db read OK.
[140635591280384] 1 db read OK.
[140635582826240] 1 db read OK.
[140635591280384] 2 db read OK.
[140635582826240] 2 db read OK.
[140635591280384] 3 db read OK.
[140635582826240] 3 db read OK.
[140635591280384] 4 db read OK.
[140635582826240] 4 db read OK.
[140635591280384] 5 db read OK.
[140635582826240] 5 db read OK.
[140635591280384] 6 db read OK.
[140635582826240] 6 db read OK.
[140635591280384] 7 db read OK.
[140635582826240] 7 db read OK.
[140635591280384] 8 db read OK.
[140635582826240] 8 db read OK.
[140635591280384] 9 db read OK.
[140635582826240] 9 db read OK.
[140635591280384] db closed
[140635582826240] db closed
[140635565917952] 0 db write OK.
[140635565917952] 1 db write OK.
[140635565917952] 2 db write OK.
[140635565917952] 3 db write OK.
[140635565917952] 4 db write OK.
[140635565917952] 5 db write OK.
[140635565917952] 6 db write OK.
[140635565917952] 7 db write OK.
[140635565917952] 8 db write OK.
[140635565917952] 9 db write OK.
[140635565917952] db closed
[140635574372096] 0 db write OK.
[140635574372096] 1 db write OK.
[140635574372096] 2 db write OK.
[140635574372096] 3 db write OK.
[140635574372096] 4 db write OK.
[140635574372096] 5 db write OK.
[140635574372096] 6 db write OK.
[140635574372096] 7 db write OK.
[140635574372096] 8 db write OK.
[140635574372096] 9 db write OK.
[140635574372096] db closed
由上可見,不加鎖訪問數據庫返回錯誤 "database is locked"
加鎖訪問數據庫可以正常訪問了
讀寫鎖成功的起到了作用
OVER