簡體   English   中英

如何檢測sqlite3是否創建了數據庫文件?

[英]How do I detect if sqlite3 created a database file?

我正在編寫一個程序,它使用sqlite3數據庫文件來存儲其數據。 如果我打開一個數據庫文件

sqlite3_open_v2(filename, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL)

如果數據庫文件不存在,則創建該數據庫文件。 如何在打開數據庫文件之前查明數據庫文件是否存在? sqlite3 shell使用如下代碼:

  /* Go ahead and open the database file if it already exists.  If the
  ** file does not exist, delay opening it.  This prevents empty database
  ** files from being created if a user mistypes the database name argument
  ** to the sqlite command-line tool.
  */
  if( access(data.zDbFilename, 0)==0 ){
    open_db(&data, 0);
  }

但是,當access調用之后和open_db調用之前(檢查時間與使用時間)之間的另一個進程創建數據庫文件時,此代碼具有競爭條件。

另一個答案(我現在找不到)建議檢查application_iduser_version字段。 如果它們為零,則只創建一個數據庫。 我研究了這種方法,發現許多應用程序實際上並不打算在新創建的數據庫中設置這些字段,所以這種方法充其量是模糊的,我不認為它解決了我的問題。

有沒有一種方法可以確定數據庫在打開之前是否存在,而不涉及這樣的競爭條件? 如果我只能通過sqlite3查明數據庫文件是否已初始化(如在sqlite3標題中填充了截斷文件),也是可以接受的。

擁有這樣一個例程的目的是為了能夠找出是否需要在數據庫中創建我需要的所有表。 我不想意外地覆蓋另一個應用程序放置在那里的另一個文件。

示例代碼

可以在以下bash腳本中找到該問題的簡化說明。 它模擬兩個應用程序。 它們都以類似的方式工作:

  1. 創建或打開數據庫test.db
  2. 如果之前不存在數據庫,則創建一個表test並在其中寫入一行。 第一個應用程序的值為1,第二個應用程序的值為2。
  3. 打印數據庫的內容。

這是代碼:

#!/bin/sh

# sleeps are inserted to make the race conditions easier to trigger

application() {
    echo Checking if database exists...
    [ ! -f test.db ]
    status=$?
    sleep 2

    if (exit $status)
    then
        echo Database not found, making tables
        sqlite3 test.db "CREATE TABLE IF NOT EXISTS test (a);"
        sleep 2
        echo Writing initial record into database
        sqlite3 test.db "INSERT INTO test VALUES ($1);"
        sleep 2
    else
        echo Database found, checking if it belongs to me
    fi

    echo Printing content of database
    sqlite3 test.db "SELECT * FROM test;"
}

rm -f test.db
echo First test: app1 and app1 race
application 1 & (sleep 1 ; application 1)

rm -f test.db
echo Second test: app2 and app1 race
application 2 & (sleep 1 ; application 1)

我的目標是確保以下情況永遠不會發生:

  • 應用程序實例打開數據庫文件,得出結論是它未初始化並初始化它(通過創建表並寫入初始記錄),即使它已經包含來自同一應用程序的不同實例或來自不同應用程序的數據。
  • 寫入屬於不同應用程序的數據庫文件。

如果application編程正確,則每次運行只會初始化數據庫(如果之前未初始化)。 因此,您將看到的唯一輸出是僅包含第1行的數據庫或僅包含第2行的數據庫。

無法將新創建的數據庫與先前創建的空數據庫區分開來。

但是,空數據庫是唯一存在此問題的數據庫。 可以通過檢查sqlite_master表是否為空來檢測任何其他數據庫。 在事務中執行此操作並創建表,並且沒有競爭條件。

如果您第一次寫入數據庫(實際創建文件時)是設置application_id ,那么您知道任何具有其他ID的文件都不是您的。 (已注冊的申請ID是唯一的。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM