pub struct Db { /* private fields */ }Expand description
The database pool. Take it in a handler with State(db): State<Db>.
Models, queries and sql() take &db (or &mut tx inside a
Transaction). For something only sqlx can do, reach the underlying
pool with Db::sqlite or Db::postgres (with the postgres feature).
Implementations§
Source§impl Db
impl Db
Sourcepub fn sqlite(&self) -> Option<&SqlitePool>
pub fn sqlite(&self) -> Option<&SqlitePool>
The sqlx pool, when the database is SQLite.
Sourcepub async fn begin(&self) -> Result<Transaction, DbError>
pub async fn begin(&self) -> Result<Transaction, DbError>
Starts a transaction. Pass &mut tx wherever a &db goes, then
tx.commit(); dropping it without committing rolls it back.
Sourcepub async fn transaction<T, F>(&self, work: F) -> Result<T>
pub async fn transaction<T, F>(&self, work: F) -> Result<T>
Runs work in a transaction: committed when it returns Ok, rolled
back when it returns Err.
let moved = db
.transaction_retrying(3, |tx| {
Box::pin(async move {
renox::db::sql("UPDATE accounts SET balance = balance - 100 WHERE id = 1")
.execute(&mut *tx)
.await?;
renox::db::sql("UPDATE accounts SET balance = balance + 100 WHERE id = 2")
.execute(&mut *tx)
.await?;
Ok(100)
})
})
.await?;Sourcepub async fn transaction_retrying<T, F>(
&self,
attempts: u32,
work: F,
) -> Result<T>
pub async fn transaction_retrying<T, F>( &self, attempts: u32, work: F, ) -> Result<T>
Like Db::transaction, trying up to attempts times when another
transaction got in the way (SQLite busy, PostgreSQL serialization
failure or deadlock), with a short, growing pause in between. work
must be safe to run again.
Sourcepub fn retrying<'a, T, F, Fut>(
&'a self,
attempts: u32,
work: F,
) -> impl Future<Output = Result<T>> + Send + 'a
pub fn retrying<'a, T, F, Fut>( &'a self, attempts: u32, work: F, ) -> impl Future<Output = Result<T>> + Send + 'a
Runs work again (up to attempts times, with a short, growing
pause) while it fails because another transaction got in the way
(SQLite busy, PostgreSQL serialization failure or deadlock). work
opens and commits its own transaction, so unlike
Db::transaction_retrying it can borrow from the caller, and it can
roll back and still return a value (drop or rollback the
transaction instead of committing).
enum Transfer { Done, Short }
let outcome = db
.retrying(3, || async {
let mut tx = db.begin().await?;
let taken = renox::db::sql(
"UPDATE accounts SET balance = balance - ? WHERE id = ? AND balance >= ?",
)
.bind(amount) // borrowed from the caller
.bind(from)
.bind(amount)
.execute(&mut tx)
.await?;
if taken == 0 {
tx.rollback().await?;
return Ok(Transfer::Short); // rolled back, with an answer
}
renox::db::sql("UPDATE accounts SET balance = balance + ? WHERE id = ?")
.bind(amount)
.bind(to)
.execute(&mut tx)
.await?;
tx.commit().await?;
Ok(Transfer::Done)
})
.await?;Sourcepub async fn begin_immediate(&self) -> Result<Transaction, DbError>
pub async fn begin_immediate(&self) -> Result<Transaction, DbError>
A transaction that takes SQLite’s write lock at once (BEGIN IMMEDIATE), so what it reads can’t change before it writes: the
SQLite counterpart of lock_for_update. Same as begin on PostgreSQL.
Trait Implementations§
impl<'c> Executor<'c> for &'c Db
Auto Trait Implementations§
impl !RefUnwindSafe for Db
impl !UnwindSafe for Db
impl Freeze for Db
impl Send for Db
impl Sync for Db
impl Unpin for Db
impl UnsafeUnpin for Db
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<A, B, T> HttpServerConnExec<A, B> for Twhere
B: Body,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more