WARNING: This page is a guide for 2.x series.

Transaction


#readOnly block / session


Executes query in read-only mode.

val names = DB readOnly { implicit session =>
  sql"select name from emp".map { rs => rs.string("name") }.list.apply()
}

implicit val session = DB.readOnlySession
try {
  val names = sql"select name from emp".map { rs => rs.string("name") }.list.apply()
  // do something
} finally {
  session.close()
}

Of course, update operations in read-only mode will cause java.sql.SQLException.

DB readOnly { implicit session =>
  sql"update emp set name = ${name} where id = ${id}".update.apply()
} // will throw java.sql.SQLException

#autoCommit block / session


Executes query / update in auto-commit mode.

val count = DB autoCommit { implicit session =>
  sql"update emp set name = ${name} where id = ${id}".update.apply()
}

When using autoCommitSession, every operation will be executed in auto-commit mode.

implicit val session = DB.autoCommitSession
try {
  sql"update emp set name = ${name1} where id = ${id1}".update.apply() // auto-commit
  sql"update emp set name = ${name2} where id = ${id2}".update.apply() // auto-commit
} finally { session.close() }

#localTx block


Executes query / update in block-scoped transactions.

If an Exception was thrown in the block, the transaction will perform rollback automatically.

val count = DB localTx { implicit session =>
  // --- transcation scope start ---
  sql"update emp set name = ${name1} where id = ${id1}".update.apply()
  sql"update emp set name = ${name2} where id = ${id2}".update.apply()
  // --- transaction scope end ---
}

TxBoundary provides other transaction boundary instead of Exception as follows (2.2.0 or higher):

import scalikejdbc._
import scala.util.Try
import scalikejdbc.TxBoundary.Try._

val result: Try[Result] = DB localTx { implicit session =>
  Try { doSomeStaff() }
}
// localTx rolls back when `result` is `Failure`
// http://scala-lang.org/api/current/#scala.util.Try

Built-in type class instances are Try, Either and Future. You can use them by import scalikejdbc.TxBoundary,***._.


#futureLocalTx block


futureLocalTx use Future’s state as transaction boundary. If one of the Future operations was failed, the transaction will perform rollback automatically.

object FutureDB {
  implicit val ec = myOwnExecutorContext
  def updateFirstName(id: Int, firstName: String)(implicit session: DBSession): Future[Int] = {
    Future { 
      blocking {
        session.update("update users set first_name = ? where id = ?", firstName, id)
      } 
    }
  }
  def updateLastName(id: Int, lastName: String)(implicit session: DBSession): Future[Int] = {
    Future { 
      blocking {
        session.update("update users set last_name = ? where id = ?", lastName, id)
      } 
    }
  }
}

object Example {
  import FutureDB._
  val fResult = DB futureLocalTx { implicit s =>  
    updateFirstName(3, "John").map(_ => updateLastName(3, "Smith"))
  }
}

Example.fResult.foreach(println(_))
// #=> 1

or TxBoundary[Future[A]] is also available.

import scalikejdbc.TxBoundary.Future._
val fResult = DB localTx { implicit s =>  
  updateFirstName(3, "John").map(_ => updateLastName(3, "Smith"))
}

#withinTx block / session


Executes query / update in already existing transactions.

In this case, all the transactional operations (such as Tx#begin(), Tx#rollback() or Tx#commit()) should be managed by users of ScalikeJDBC.

val db = DB(conn)
try {
  db.begin()
  val names = db withinTx { implicit session =>
    // if a transaction has not been started, IllegalStateException will be thrown
    sql"select name from emp".map { rs => rs.string("name") }.list.apply()
  }
  db.rollback() // it might throw Exception
} finally { db.close() }

val db = DB(conn)
try {
  db.begin()
  implicit val session = db.withinTxSession()
  val names = sql"select name from emp".map { rs => rs.string("name") }.list.apply()
  db.rollbackIfActive() // it NEVER throws Exception
} finally { db.close() }

If this webpage has a typo or something wrong, Please report or fix it. How?