尝试从PHP脚本访问时数据库被锁定


Database locked while trying to access from PHP script

我正在编写一个与PHP后端通信的Android应用程序。后端数据库是SQLite 3。问题是,我间歇性地收到这个错误PHP Warning: SQLite3::prepare(): Unable to prepare statement: 5, database is locked。我在每个PHP文件中打开一个到数据库的连接,并在脚本完成时关闭它。我认为问题是,一个脚本在写入数据库文件时锁定了数据库文件,而第二个脚本试图访问它,但失败了。避免这种情况的一种方法是在所有php脚本之间共享连接。我想知道是否还有其他方法可以避免这种情况?

编辑:这是第一个文件:

<?php
$first = SQLite3::escapeString($_GET['first']);
$last = SQLite3::escapeString($_GET['last']);
$user = SQLite3::escapeString($_GET['user']);
$db = new SQLite3("database.db");
$insert = $db->prepare('INSERT INTO users VALUES(NULL,:user,:first,:last, 0 ,datetime())');
$insert->bindParam(':user', $user, SQLITE3_TEXT);
$insert->bindParam(':first', $first, SQLITE3_TEXT);
$insert->bindParam(':last', $last, SQLITE3_TEXT);
$insert->execute();
?>

这是第二个文件:

<?php
$user = SQLite3::escapeString($_GET['user']);
$db = new SQLite3("database.db");
$checkquery = $db->prepare('SELECT allowed FROM users WHERE username=:user');
$checkquery->bindParam(':user', $user, SQLITE3_TEXT);
$results = $checkquery->execute();
$row = $results->fetchArray(SQLITE3_ASSOC);
print(json_encode($row['allowed']));
?>

首先,当你处理完一个资源时,你应该总是关闭它。理论上,当它被垃圾收集时,它会被关闭,但你不能依赖PHP立即关闭。我见过一些数据库(以及其他类型的库)因为没有明确发布资源而被锁定。

$db->close();
unset($db);

其次,Sqlite3会给您一个繁忙超时。我不确定默认值是什么,但如果你愿意在执行查询时等待几秒钟以清除锁定,你可以这么说。超时以毫秒为单位。

$db->busyTimeout(5000);

我一直处于"数据库锁定"状态,直到我发现sqlite3的一些功能必须使用SQL特殊指令(即使用PRAGMA关键字)进行设置。例如,显然解决了我的"数据库锁定"问题的是将journal_mode设置为"wal"(默认为"delete",如下所述:https://www.sqlite.org/wal.html(请参阅激活和配置WAL模式))。

所以基本上我要做的就是创建一个到数据库的连接,并用SQL语句设置journal_mode。示例:

<?php
  $db = new SQLite3('/my/sqlite/file.sqlite3');
  $db->busyTimeout(5000);
  // WAL mode has better control over concurrency.
  // Source: https://www.sqlite.org/wal.html
  $db->exec('PRAGMA journal_mode = wal;');
?>

希望能有所帮助。