插入期间 SQLite 错误“尝试写入只读数据库”?

Posted

技术标签:

【中文标题】插入期间 SQLite 错误“尝试写入只读数据库”?【英文标题】:SQLite error 'attempt to write a readonly database' during insert? 【发布时间】:2011-03-20 03:31:19 【问题描述】:

我有一个用于网站的 SQLite 数据库。问题是当我尝试INSERT INTO 它时,我得到一个PDOException

SQLSTATE[HY000]: General error: 8 attempt to write a readonly database

我通过 SSH 连接到服务器并检查了权限,并且数据库具有权限

-rw-rw-r--

我对 *nix 权限不太熟悉,但我很确定这意味着

不是目录 所有者拥有读/写权限(根据ls -l,就是我) 组具有读/写权限 其他人只有读取权限

我还查看了使用sqlite3 程序的所有我知道的地方,但没有发现任何相关内容。

因为我不知道 PDO 试图打开数据库的权限是什么,所以我做到了

chmod o+w supplies.db

现在,我又收到了一个PDOException

SQLSTATE[HY000]: General error: 14 unable to open database file

但只有当我尝试在数据库打开之后执行INSERT 查询时才会发生这种情况。

有什么想法吗?

【问题讨论】:

基本上 httpd (apache > php > PDO) 不是你,所以它不拥有文件,所以它没有写权限...有趣... sudo chgrp www-data test.db 添加权限对我有用 如果您尝试访问已删除的数据库,也会显示此错误 【参考方案1】:

事实证明,问题在于 PDO SQLite 驱动程序要求如果您要执行写入操作(INSERTUPDATEDELETEDROP 等),那么数据库所在的文件夹必须具有写入权限,以及实际的数据库文件。

我在comment at the very bottom of the PDO SQLite driver manual page 中找到了此信息。

【讨论】:

此外,SELinux(如果已安装)不得强制执行。我花了一天半的时间才弄明白。 嗯,对不起,但我感谢它,但它只是暂时解决了问题,主要问题是我的 www-data 用户不在 www-data 组中。 据我所知,包含文件夹必须是可写的,因为在写入日志文件时将创建数据库本身。要拥有与网络服务器相同的用户,请尝试将文件的内容复制到另一个创建的 ad hoc。 另外,db 文件及其所在的目录必须由 linux 机器上的“www-data”拥有。 目前 sqlite3 可能有 3 个文件,.db,一个.db-shm 和一个.db-wal 文件,当然还有这三个文件的父目录,对于运行的用户必须都是可写的程序。【参考方案2】:

当 SQLite 文件本身的所有者与运行脚本的用户相同时,可能会发生这种情况。如果无法写入整个目录路径(即沿途的每个目录),则可能会发生类似的错误。

谁拥有 SQLite 文件?你呢?

脚本以谁的身份运行?阿帕奇还是没人?

【讨论】:

我拥有 SQLite 文件,但我不知道脚本以谁的身份运行。我怎样才能知道? (请记住,这是在共享主机上,我的权限有限) 啊,这让事情变得更有趣了。如果您使用的是共享主机,则脚本很有可能以“nobody”或“apache”的身份运行。让您的脚本创建一个文件 (file_put_contents('./foo.txt', 'Hello, world');),该文件将向您显示它以谁的身份运行。您可能需要让脚本创建 SQLite 数据库。如果您的当前文件中已经有数据,这可能是一个有趣的练习... 好主意,但不行。运行 PHP 的人没有写入权限,因此无法创建文件。无论如何PHP可以检索它当前运行的用户吗? 唯一的方法似乎是through the POSIX extension,它在 POSIX-y 系统上默认启用。不过,您的托管服务提供商可能有 R'd TFM 并禁用了它。 好吧,他们研发了 TFM,好吧。 posix_getuid() 也不起作用。【参考方案3】:

对我来说,问题是SELinux enforcement 而不是权限。根据 Steve V. 在 the accepted answer.

的评论中提出的建议,一旦我禁用强制执行,“只读数据库”错误就会消失
echo 0 >/selinux/enforce

运行此命令后,一切都按预期运行(CentOS 6.3)。

我遇到的具体问题是在设置 Graphite 期间。我已经三重检查了 apache 用户是否拥有并且可以写入我的石墨.db 及其父目录。但是在我“修复” SELinux 之前,我得到的只是一个堆栈跟踪,其效果是:DatabaseError: attempt to write a readonly database

【讨论】:

SELinux 是一种安全措施,因此不应在没有充分理由的情况下禁用。最好首先弄清楚 SELinux 阻塞的原因并正确配置它而不是禁用它。【参考方案4】:

这可能是由 SELinux 引起的。如果不想完全禁用 SELinux,则需要将 db 目录 fcontext 设置为 httpd_sys_rw_content_t。

semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/railsapp/db(/.*)?"
restorecon -v /var/www/railsapp/db

【讨论】:

【参考方案5】:

当我尝试在 android 系统上写入数据库时​​遇到此错误。

显然 sqlite3 不仅需要对数据库文件和包含目录的写权限(正如@austin-hyde 在他的回答中已经说过的那样),而且环境变量TMPDIR 必须指向一个(可能是可写的)目录。

在我的 Android 系统上,我将其设置为 TMPDIR="/data/local/tmp",现在我的脚本按预期运行 :)

编辑:

如果您无法设置环境变量,您可以使用此处列出的其他方法之一:https://www.sqlite.org/tempfiles.html#temporary_file_storage_locations 喜欢PRAGMA temp_store_directory = 'directory-name';

【讨论】:

【参考方案6】:

我在 Windows 7 下从 IIS 得到了同样的错误。要修复这个错误,我必须为 sqlite 数据库文件的 IUSR 帐户添加完全控制权限。如果您在 webmatrix 下使用 sqlite 而不是 IIS,则无需更改权限。

【讨论】:

【参考方案7】:

总之,我通过将数据库文件 (* .db) 放在子文件夹中解决了这个问题。

子文件夹和其中的数据库文件必须是 www-数据组。 在 www-data 组中,您必须有权写入 子文件夹和数据库文件。

【讨论】:

【参考方案8】:

我用过:

echo exec('whoami');

找出谁在运行脚本(比如用户名),然后授予用户对整个应用程序目录的权限,例如:

sudo chown -R :username /var/www/html/myapp

【讨论】:

【参考方案9】:

当我从使用 http://localhost 更改为 http://145.900.50.20(其中 145.900.50.20 是我的本地 IP 地址)然后又改回 localhost 时,我在浏览器中得到了这个 - 有必要保留一次 IP 地址我曾经改变过一次

【讨论】:

【参考方案10】:

(对于寻找类似问题答案的追随者) 我正在构建一个 C# .Net Core 6.0 WPF 应用程序。为了开发方便,我把Sqlite.db3放在c:\盘。要写入数据库,我必须以管理员身份打开 Visual Studio 2019。

【讨论】:

以上是关于插入期间 SQLite 错误“尝试写入只读数据库”?的主要内容,如果未能解决你的问题,请参考以下文章

Django 登录错误:在 IIS 中“尝试写入只读数据库”

尝试写入只读数据库(代码 1032)

将 SQLite 数据库模式更改为读写

BEGIN IMMEDIATE 可能在 0:8/尝试写入只读数据库后意外无法步进

当 iPhone 应用程序在向表中插入数据时或期间退出时,如何回滚 SQLite DB?

execSQL()期间的SQLite数据库错误