diff --git a/CHANGELOG.md b/CHANGELOG.md index 098244902..1dfa0c98d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - use transaction in `Contact::add_or_lookup()` #4059 ### Fixes +- Start SQL transactions with IMMEDIATE behaviour rather than default DEFERRED one. #4063 ### API-Changes diff --git a/src/sql.rs b/src/sql.rs index 6d6a53fec..4b4b190eb 100644 --- a/src/sql.rs +++ b/src/sql.rs @@ -6,7 +6,7 @@ use std::path::Path; use std::path::PathBuf; use anyhow::{bail, Context as _, Result}; -use rusqlite::{self, config::DbConfig, Connection, OpenFlags}; +use rusqlite::{self, config::DbConfig, Connection, OpenFlags, TransactionBehavior}; use tokio::sync::RwLock; use crate::blob::BlobObject; @@ -377,6 +377,12 @@ impl Sql { /// /// If the function returns an error, the transaction will be rolled back. If it does not return an /// error, the transaction will be committed. + /// + /// Transactions started use IMMEDIATE behavior + /// rather than default DEFERRED behavior + /// to avoid "database is busy" errors + /// which may happen when DEFERRED transaction + /// is attempted to be promoted to a write transaction. pub async fn transaction(&self, callback: G) -> Result where H: Send + 'static, @@ -384,7 +390,7 @@ impl Sql { { let mut conn = self.get_conn().await?; tokio::task::block_in_place(move || { - let mut transaction = conn.transaction()?; + let mut transaction = conn.transaction_with_behavior(TransactionBehavior::Immediate)?; let ret = callback(&mut transaction); match ret {