updateの更新結果件数を見てcommit or rollbackなんかしたかったので、明示的にbegin, rollback, commitできるインターフェースが欲しかった。
ちょっと探してみたけど、見当たらなくて、transaction_builder
なんてものもあったけど、どうやら隔離レベルを指定するインターフェースみだいだし、Trait diesel::connection::TransactionManager
はパブリックじゃないっぽい。
追記:AnsiTransactionManager
で明示的にトランザクションセッションを張れる。っぽい(コンパイルのみ確認。動作確認はしていない)。
use diesel::connection::{AnsiTransactionManager, TransactionManager}; let ansi = AnsiTransactionManager::new(); ansi.begin_transaction(&conn); ansi.commit_transaction(&conn); ansi.rollback_transaction(&conn);
ここから先は追記前。
ちょっとわからなかったので自前でトランザクションセッションを張れる処理を書いた。
トランザクション管理
transaction.rs
use crate::repositories::connection::DBConnection; use diesel::dsl::sql; use diesel::sql_types::{Bool, Integer, Text}; use diesel::RunQueryDsl; use diesel::QueryResult; pub struct Transaction<'a> { db: &'a DBConnection<'a> } impl <'a>Transaction<'a> { pub fn new(db: &'a DBConnection) -> Self { Transaction{db} } pub fn begin(&self) -> QueryResult<usize>{ let setup = sql::<Bool>("begin"); let db = self.db.get(); setup.execute(db) } pub fn commit(&self) -> QueryResult<usize>{ let setup = sql::<Bool>("commit"); let db = self.db.get(); setup.execute(db) } pub fn rollback(&self) -> QueryResult<usize>{ let setup = sql::<Bool>("rollback"); let db = self.db.get(); setup.execute(db) } }
use repositories::connection::DBConnection;
は自前のDBインスタンスの抽象なだけなので、PgConnectionなりMySQLConnectionなりに読み替えて下さい。見てわかる通り平たいSQL喋ってるだけ笑
結構、探したんだけどやり方わからなくて、こりゃSQL喋ったほうが早いなと思ってこっちの方針にした。
使い方
これもrepositoryやself.connなんか出てくるけど、中でPgConnectionでクエリ発行してるだけなので、トランザクションセッションを張る接続でクエリ投げて結果を見て、commit or rollbackするようなカジュアルな感じ。
use.rust
let transaction = Transaction::new( self.conn ); let result = transaction.begin().and_then(|_| { self.account_repository.save( &account ).and_then(|_| { self.team_repository.save( &team ) }) }); let ans = match result { Err(error) => { transaction.rollback().expect(""); error.to_string() }, Ok(id) => { transaction.commit().expect("commitに失敗しました"); id } };
追記の通りTransactionManager
でトランザクション張るのでいいんだけど、結局モックオブジェクトに差し替えたかったりで、自前の使ってしまってる(^_^;)