clean-architecture-buckpal-rust
clean-architecture-buckpal-rust copied to clipboard
What about DB transactions?
How are you dealing with DB transactions?
Hi @frederikhors! Forgive me as it's been quite a while since I touched this repo.
There are ways with sqlx to deal with transactions I regularly dip into now in my professional work.
Here's one of their official examples: https://github.com/launchbadge/sqlx/blob/main/examples/postgres/transaction/src/main.rs
Can't quite remember what the source book did with transactions, but if you need to store / pass them around you might be able to do so with a generic that implements the Transaction trait. Maybe an Arc/Mutex to wrap it if that becomes necessary. What's your use case?
Hi @jayy-lmao I'm talking about transactions across business usecases (the services layer): imagine "wallet" along with your existing "account".
Example:
-
move money from an account to another;
-
wait for each wallet during the transfer.
So you would definitely need a Arc, Mutex, and an optional. You would need to be careful that you have not created a singleton, but rather a per-request.
Or you may be able to do this by making it an argument at either the service or repository layer, then passing around the tx object.
e.g.
impl AbstractWalletService for WalletService {
fn check_wallet_balance(&self, tx: &mut Transaction<'_, Postgres>) -> anyhow::Result<bool> {
todo!()
}
}
Then in your handler or whichever you would do
let mut tx = db.pool.begin().await?;
let result = check_wallet_balance(&mut tx)?;
// further down once you've done all your operations
tx.commit()
Of course you may want to do this at a Service level instead, in which case it would just be the same thing with your repository functions.
Its worth being aware that you can also alternatively use the Executable trait as a trait bound if you wanted your functions to accept either a transaction or a regular pool reference.