import scalikejdbc._ class DBService @Inject()(implicit ec: DBExecutionContext) { def multiUpdateInTransaction: Future[List[Int]] = { DB.futureLocalTx { implicit session => val ids = sql"""select id from members""".map(rs => rs.long("id")).toList().apply() Future.sequence(ids.map { id => val newName = s"userId$id" Future(sql"""update members set name = $newName where id = $id""".update.apply()) }) } } } ※コードを簡略化するために、DBアクセス部分をScalikejdbcを使っています
import scalikejdbc._ class DBService @Inject()(implicit ec: DBExecutionContext) { def multiUpdateInTransaction: Future[List[Int]] = { DB.futureLocalTx { implicit session => val ids = sql"""select id from members""".map(rs => rs.long("id")).toList().apply() Future.sequence(ids.map { id => val newName = s"userId$id" Future(sql"""update members set name = $newName where id = $id""".update.apply()) }) } } } ①. DBのトランザクションを開始し、引数の関数が返す Futureが完了したらトランザクションをコミット。 失敗したらロールバック ①
import scalikejdbc._ class DBService @Inject()(implicit ec: DBExecutionContext) { def multiUpdateInTransaction: Future[List[Int]] = { DB.futureLocalTx { implicit session => val ids = sql"""select id from members""".map(rs => rs.long("id")).toList().apply() Future.sequence(ids.map { id => val newName = s"userId$id" Future(sql"""update members set name = $newName where id = $id""".update.apply()) }) } } } ①. DBのトランザクションを開始し、引数の関数が返す Futureが完了したらトランザクションをコミット。 失敗したらロールバック ① ②. DBから取得したIDのリストを使って、複数の updateを実行するFuture生成し、それを Future.sequenceを使って一つのFutureにまとめる 基のFutureの結果をまとめるだけなので、それぞれの Futureは別スレッドで実行される ②
import scalikejdbc._ class DBService @Inject()(implicit ec: ExecutionContext) { def multiUpdateInTransaction: Future[List[Int]] = { DB.futureLocalTx { implicit session => val ids = sql"""select id from members""".map(rs => rs.long("id")).toList().apply() Future.sequence(ids.map { id => val newName = s"userId$id" Future(sql"""update members set name = $newName where id = $id""".update.apply()) }) } } } ①. DBのトランザクションを開始し、引数の関数が返す Futureが完了したらトランザクションをコミット。 失敗したらロールバック ① ② updateを複数のスレッドで並列実行できるので速くなりそうに見えるが、 短時間に複数のスレッドからこのメソッドが呼び出されると、DBのロック解放待ち状態の スレッドが大量にできて、しばらくこのExecutionContextは処理を実行できなくなる ②. DBから取得したIDのリストを使って、複数の updateを実行するFuture生成し、それを Future.sequenceを使って一つのFutureにまとめる 基のFutureの結果をまとめるだけなので、それぞれの Futureは別スレッドで実行される