- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
在我的 Rust 应用程序中,我使用 Diesel
与 SQLite
数据库进行交互。我有多个线程可以同时查询数据库,我正在使用 crate r2d2
创建一个连接池。
我遇到的问题是我无法同时查询数据库。如果我尝试这样做,我总是会收到错误 database is locked
,这是不可恢复的(即使只有一个线程在查询,任何后续请求也会因相同的错误而失败)。
以下代码重现了该问题。
# Cargo.toml
[dependencies]
crossbeam = { version = "0.7.1" }
diesel = { version = "1.4.2", features = ["sqlite", "r2d2"] }
-- The database table
CREATE TABLE users (
name TEXT PRIMARY KEY NOT NULL
);
#[macro_use]
extern crate diesel;
mod schema;
use crate::schema::*;
use crossbeam;
use diesel::r2d2::{ConnectionManager, Pool};
use diesel::RunQueryDsl;
use diesel::{ExpressionMethods, SqliteConnection};
#[derive(Insertable, Queryable, Debug, Clone)]
#[table_name = "users"]
struct User {
name: String,
}
fn main() {
let db_url = "test.sqlite3";
let pool = Pool::builder()
.build(ConnectionManager::<SqliteConnection>::new(db_url))
.unwrap();
crossbeam::scope(|scope| {
let pool2 = pool.clone();
scope.spawn(move |_| {
let conn = pool2.get().unwrap();
for i in 0..100 {
let name = format!("John{}", i);
diesel::delete(users::table)
.filter(users::name.eq(&name))
.execute(&conn)
.unwrap();
}
});
let conn = pool.get().unwrap();
for i in 0..100 {
let name = format!("John{}", i);
diesel::insert_into(users::table)
.values(User { name })
.execute(&conn)
.unwrap();
}
})
.unwrap();
}
这是应用程序崩溃时显示的错误:
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: DatabaseError(__Unknown, "database is locked")'
AFAIK,我应该能够使用多线程连接池(即,多线程的多个连接),如 r2d2_sqlite
crate example 所示.
此外,我在系统中安装的sqlite3库支持Serialized线程模型,来自here :
In serialized mode, SQLite can be safely used by multiple threads with no restriction.
如何避免 database is locked
错误?另外,如果由于任何原因无法避免这些错误,我该如何解锁数据库?
最佳答案
最近我也偶然发现了这个问题。这是我的发现。
SQLite 不支持多个作者。
来自文档:
When SQLite tries to access a file that is locked by another process, the default behavior is to return SQLITE_BUSY.
那么如何绕过这个限制呢?我看到了两种解决方案。
您可以多次重试查询,直到获得锁。事实上 SQLite 提供了 built-in mechanism .您可以指示 SQLite 多次尝试锁定数据库。
现在您唯一需要做的就是以某种方式将此 pragma 传递给 SQLite。幸运的是,diesel::r2d2
提供了一种简单的方法来通过新建立的连接的初始设置:
#[derive(Debug)]
pub struct ConnectionOptions {
pub enable_wal: bool,
pub enable_foreign_keys: bool,
pub busy_timeout: Option<Duration>,
}
impl diesel::r2d2::CustomizeConnection<SqliteConnection, diesel::r2d2::Error>
for ConnectionOptions
{
fn on_acquire(&self, conn: &mut SqliteConnection) -> Result<(), diesel::r2d2::Error> {
(|| {
if self.enable_wal {
conn.batch_execute("PRAGMA journal_mode = WAL; PRAGMA synchronous = NORMAL;")?;
}
if self.enable_foreign_keys {
conn.batch_execute("PRAGMA foreign_keys = ON;")?;
}
if let Some(d) = self.busy_timeout {
conn.batch_execute(&format!("PRAGMA busy_timeout = {};", d.as_millis()))?;
}
Ok(())
})()
.map_err(diesel::r2d2::Error::QueryError)
}
}
// ------------- Example -----------------
let pool = Pool::builder()
.max_size(16)
.connection_customizer(Box::new(ConnectionOptions {
enable_wal: true,
enable_foreign_keys: true,
busy_timeout: Some(Duration::from_secs(30)),
}))
.build(ConnectionManager::<SqliteConnection>::new(db_url))
.unwrap();
您可能想要使用的第二个变体是 WAL 模式。它通过让读者和作者同时工作来提高并发性(WAL 模式比默认日志模式快很多)。但是请注意,忙碌超时是 still required为了让所有这些都起作用。
(请同时阅读 "synchronous" 模式设置为“正常”的后果。)
SQLITE_BUSY_SNAPSHOT是 WAL 模式下可能发生的事情。但是有一个简单的补救方法 - 使用 BEGIN IMMEDIATE
以写入模式启动事务。
这样你就可以拥有多个读者/作者,这让生活更轻松。多个写入者使用锁定机制(通过busy_timeout
),因此此时只有一个活跃的写入者。您当然不希望将连接限定为读写并在您的应用程序中手动进行锁定,例如使用 Mutex
。
关于database - 如何将 Diesel 与 SQLite 连接一起使用并避免 `database is locked` 类型的错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57123453/
我想知道锁是如何在 Java 中实现的。在一些教程中,我发现它们应该使用 wait() 和 notify()/notifyAll() 以及一些 boolean 标志来实现(它可能比那复杂得多,但基本上
我正在开发一个多线程服务器,用于存储和读取来自数据库的信息。数据库是用 RocksDB 实现的。 我遇到的问题是,当我一次从多个线程访问数据库时,我得到了那个错误。 通常是说db在usign后没有被删
例如,这里有一些 linux 中的代码: void set_leds(int val) { int fd = open ("/dev/console", O_WRONLY); // argumen
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 9 年前。 Improve this qu
考虑以下代码。为了防止IndexOutOfBoundsException打电话时 listIterator ,我们使用读取器锁来检索基于索引的 iteartor,并在对 stockCodes 进行写操
这个问题在这里已经有了答案: Java locking structure best pattern (2 个答案) 关闭 6 年前。 有什么区别: private Lock lock = new
是否可以在网页加载时检查 Scroll Lock、Num Lock 和 Caps Lock 的状态?我找到了使用 JavaScript 在按键后进行检查的方法,但这不是我要问的。 最佳答案 2019
是否可以在网页加载时检查 Scroll Lock、Num Lock 和 Caps Lock 的状态?我找到了使用 JavaScript 在按键后进行检查的方法,但这不是我要问的。 最佳答案 2019
在Ubuntu中安装某些东西时出现错误。我尝试了一些命令来杀死正在运行的进程,但仍然遇到相同的错误。 最佳答案 根据文章How to Fix “Waiting for cache lock: Coul
我们有一个gradle构建,它可以动态创建GradleBuild类型的多个任务,以与不同的客户端库版本一起运行以测试其兼容性。在Gradle4上可以正常工作,但是在移至Gradle5后,执行第一项任务
我在尝试运行在 vertica 数据库表上运行查询的客户端应用程序时反复遇到此错误。 有人可以帮助解决这个问题吗? 最佳答案 我想知道您的客户端应用程序向 Vertica 发送了哪种“查询”(以 RE
我有一个创建锁的方法。 ReadWriteLock lock = new ReentrantReadWriteLock(); 然后我使用 Lock Interface 将该对象传递到一个方法中。 m
正如问题所问,我知道这是可能的on Linux ,但我找不到任何适用于 Windows 的最新信息。有可能吗? 最佳答案 您可以使用 ctypes 加载 user32.dll 然后调用 GetKeyS
这是同一个问题 Change keyboard locks in Python或者 How to change caps lock status without key press . 但还是有区别的
与 this question 相同,不知道为什么Java团队没有在Lock中添加一些默认方法界面,类似这样: public default void withLock(Runnable r) {
我有一个带有package-lock.json文件的项目。 现在,我想基于yarn.lock文件或项目的现有package-lock.json生成node_modules文件。 我怎样才能做到这一点?
我正在查看 pthreadtypes.h 文件中的 pthread_mutex_t 结构。 “__lock”代表什么?它就像分配给互斥锁的锁号吗? typedef union { struct _
我正在研究避免死锁的措施,其中一种可能的方法是通过强制线程放弃它在访问另一个锁但无法访问该锁时已经持有的锁来打破循环等待。 以最简单的银行账户转账为例: class Account { priva
我被要求支持一些遗留代码,我看到了一些让我摸不着头脑的事情。在某些代码段中,我看到类实例使用 CMutex 实例来同步方法执行。例如 class CClassA : public CObject {
当我们调用 lock.lock() 或尝试进入一个 synchronized block 时,如果其他线程已经获取了该锁,我们的线程就会阻塞。现在我的问题是,当我们查看 lock.lock() 的实现
我是一名优秀的程序员,十分优秀!