Reputation: 1471
I want to be able to surround a block of code with a transaction. The calling code should be as simple as this:
transactional {
save("something")
}
I thought to make the transactional
function like this:
def transactional(block: => Unit): Unit = {
implicit val conn: Connection = ???
conn.begin()
try {
block
conn.commit()
} catch {
case ex: Exception =>
conn.rollback()
throw ex
} finally {
conn.close()
}
}
Now the save
method will need to do something with the Connection, but I want to make the calling code agnostic of that (see above). I naively implemented it like this:
def save(operation: String)(implicit conn: Connection): Unit = {
println(s"saving $operation using $conn")
}
Of course I get a compilation error, that the Connection can not be found. What part am I missing to wire the Connection from the transactional
function to the save
function?
Upvotes: 1
Views: 70
Reputation: 14825
Change your transactional
function something like below (look at the code snippet of transactional). The problem here is connection is available with transactional but it has to reach save function implicitly. So once you get the connection object hand it to the a function which runs inside the transaction and then this code (f) can get access to the connection. Once f gets access to the connection we can make it implicit
using the implicit keyword. Now functions like save which take connection implicitly can seamlessly be called inside the transactional.
Important changes to transactional
1) Instead of passing the code block (block: => Unit) pass f (f: Connection => Unit)
2) Inside transactional apply f to connection object and give f access to the connection object.
def transactional(f: Connection => Unit): Unit = {
val conn = getConnectionFromDatabase()
conn.begin()
try {
f(conn)
conn.commit()
} catch {
case ex: Exception =>
conn.rollback()
throw ex
} finally {
conn.close()
}
}
Now you can use it like this
transactional { implicit conn =>
save("something")
}
if you save function is like this
def save(str: String): Connection => Unit = ???
Then you can go without connection
transactional(save("foo"))
Upvotes: 2
Reputation: 37822
You can do that without using implicit
, and without changing the calling code, if save
returns a function expecting a Connection:
def transactional(block: Connection => Unit): Unit = {
val conn: Connection = ???
// stuff..
block(conn)
// stuff..
}
def save(operation: String): Connection => Unit = { conn =>
println(s"saving $operation using $conn")
}
transactional {
save("something")
}
Upvotes: 1