You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust使用sqlx并行操作SQLite如何等待解锁避免锁报错

SQLite高并发下database is locked错误解决方法

核心原因

SQLite默认锁等待超时为0,即遇到锁冲突时直接返回SQLITE_BUSY(错误码5)错误,不会自动等待锁释放。同时sqlx默认的SQLite连接配置、连接池参数没有针对高并发场景做优化,协程量上来后大量连接同时抢锁就会触发报错。

具体配置步骤

  • 设置锁等待超时(必做)
    直接在数据库连接串中添加busy_timeout参数,单位为毫秒,该参数会告诉SQLite驱动遇到锁时最长等待多久再返回错误,而非立刻失败。比如设置5秒等待:

    // 原连接串替换为带参数的版本
    let conn_str = "sqlite://database.db?busy_timeout=5000";
    

    并发量越高可以适当调大该值,日常场景设置3000-10000即可。

  • 限制连接池最大连接数(必做)
    SQLite是文件级数据库,写操作天然串行执行,连接数过大只会加剧锁竞争,不会提升性能,建议最大连接数设置为4-8即可。不要使用默认的SqlitePool::connect直接建连,改用SqlitePoolOptions自定义池参数:

    use sqlx::sqlite::SqlitePoolOptions;
    use std::time::Duration;
    
    let pool = SqlitePoolOptions::new()
        .max_connections(8) // 最大连接数不要超过10
        .acquire_timeout(Duration::from_secs(10)) // 对应调大连接获取超时
        .connect("sqlite://database.db?busy_timeout=5000")
        .await
        .unwrap();
    
  • 开启WAL模式(强烈推荐)
    SQLite默认使用回滚日志模式,读写操作会互相阻塞,并发能力极差。开启WAL(预写日志)模式后,读操作不会阻塞写、写操作也不会阻塞读,能大幅降低锁冲突概率。连接初始化时执行一次如下语句即可:

    // 仅需执行一次,配置会持久化到数据库文件,重复执行无副作用
    sqlx::query("PRAGMA journal_mode=WAL;")
        .execute(&pool)
        .await
        .unwrap();
    
  • 优化事务逻辑(日常注意)
    如果后续使用手动事务,不要在事务内执行非数据库的异步等待操作(比如IO请求、sleep),避免长时间持有写锁,导致其他操作等待超时。单条语句默认自动提交,执行完会立刻释放锁,你当前示例代码的逻辑不存在这个问题。

效果说明

配置完成后,协程发起数据库请求时会先在连接池侧排队获取连接,拿到连接后如果遇到锁被占用,驱动会自动等待锁释放,直到超时才会返回错误,不会出现一碰到锁就直接抛出database is locked的问题。


内容的提问来源于stack exchange,提问作者Yoskutik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 17:09:17