sydboraa sydboraa - 4 months ago 57
Scala Question

Do own stuff in Slick transaction

I'm using Slick 3.1.1 and i would like to implement my own stuff on Slick transaction.

def findSomeProducts = table.getSomeProducts() //db operation
def productTableUpdate = doSomeStuff1() //db operation
def priceTableUpdate = doSomeStuff2() //db operation

def updateElasticCache = updateIndexOfProduct() //this is not a database operation

I have these sample functions. Firstly, I'm getting some products from db and after i'm updating the tables. At the end I need to run updateElasticCache method. If updateElasticCache method fails, I would like to rollback whole db procceses.

I can't use
(for { ... } yield ()).transactionally
this code because it's not applicable for my cases. This 'transactionally' is waiting a db action. But I want to add another functionality which is not a db-process.

Is it possible? How can I achieve it?



Yes !!! its possible to add non db logic in between db logic in slick using DBIO actions composition and DBIO.from

Note that "your own stuff" should return a future, future can be converted to DBIO and can be composed along with usual db actions.

DBIO.from can help you with this. Here is how it works. DBIO.from takes a future and converts it into a DBIOAction. now you can compose these actions with usual db actions to do non-db operations along with db operations in a transaction.

def updateElasticCache: Future[Unit] = Future(doSomething())

now lets say we have some db actions

def createUser(user: User): DBIO[Int] = ???

I want createUser to rollback if updating cache fails. so i do the following

val action = createUser.flatMap { _ => DBIO.from(updateElasticCache()) }.transactionally

now if updateElasticCache fails whole tx will fail and everything will rollback to normal state.


You can use for comprehension to make it look good

def updateStats: DBIO[Int] = ???
val rollbackActions =
  (for {
     cStatus <- createUser()
     uStatus <- updateStats()
     result <- DBIO.from(updateElasticCache())
   } yield result).transactionally

everything roll backs if updateElasticCache future fails