Connection Pool
Configuration
For details on setting up your connection pool, please visit the /documentation/configuration page.
Borrowing Connections
To borrow a connection, simply use the #borrow()
method:
import scalikejdbc._
// default connection
val conn: java.sql.Connection = ConnectionPool.borrow()
// named connection
val conn: java.sql.Connection = ConnectionPool("named").borrow()
It is important to manually release the connection. To prevent errors, employing the so-called loan pattern is recommended:
using(ConnectionPool.borrow()) { conn =>
// do something
}
ScalikeJDBC encapsulates a java.sql.Connection
in a scalikejdbc.DB
object for safer, easier management:
using(DB(ConnectionPool.borrow())) { db =>
// perform database operations
}
The DB
object simplifies managing DBSession
for different operations:
using(DB(ConnectionPool.borrow())) { db =>
db.readOnly { implicit session =>
// read-only operations
}
}
However, this can be made simpler by directly using the DB
or NamedDB
objects, which is the most common way to use this library:
// default
DB readOnly { implicit session =>
// ...
}
// named
NamedDB("named") readOnly { implicit session =>
// ...
}
Reusing same DB instance several times
By default, scalikejdbc.DB
or scalikejdbc.NamedDB
instance closes its connection automatically (= releases and returns it to connection pools).
using(connectionPool.borrow()) { (conn: java.sql.Connection) =>
val db: DB = DB(conn)
db.localTx { implicit session =>
sql"update something set name = ${name} where id = ${id}".update.apply()
} // localTx or other APIs always close the connection to avoid connection leaks
// Connection is already closed here, using it again will throw an SQLException!
db.localTx { implicit session =>
// ....
}
}
To reuse the same connection without returning it to the connection pool, disable auto-close through DB#autoClose(Boolean)
:
using(connectionPool.borrow()) { (conn: java.sql.Connection) =>
val db: DB = DB(conn)
// set as auto-close disabled
db.autoClose(false)
db.localTx { implicit session =>
sql"update something set name = ${name} where id = ${id}".update.apply()
} // localTx won't close the current Connection
// Reuse the connection for another transaction
db.localTx { implicit session =>
// ....
}
}
Thread-local Connection Pattern
Connections can be managed as thread-local variables, needing explicit closure (meaning you’re responsible to manually close the session):
def init() = {
val newDB = ThreadLocalDB.create(conn)
newDB.begin()
}
// after that..
def action() = {
val db = ThreadLocalDB.load()
}
def finalize() = {
try { ThreadLocalDB.load().close() } catch { case e => }
}
Replacing ConnectionPool on Runtime
ConnectionPool settings can be safely changed at runtime without disrupting existing connections:
def doSomething = {
ConnectionPool.singleton("jdbc:h2:mem:db1", "user", "pass")
DB localTx { implicit s =>
// long transaction...
// overwrite singleton CP
ConnectionPool.singleton("jdbc:h2:mem:db2", "user", "pass")
// db1 connection pool is still available until this trancation is committed.
// Newly borrowed connections will access db2.
}
}
Using Another ConnectionPool Implementation
To utilize a different connection pool provider, such as c3p0, define your own ConnectionPoolFactory
:
/**
* c3p0 Connection Pool Factory
*/
object C3P0ConnectionPoolFactory extends ConnectionPoolFactory {
override def apply(url: String, user: String, password: String,
settings: ConnectionPoolSettings = ConnectionPoolSettings()) = {
new C3P0ConnectionPool(url, user, password, settings)
}
}
/**
* c3p0 Connection Pool
*/
class C3P0ConnectionPool(
override val url: String,
override val user: String,
password: String,
override val settings: ConnectionPoolSettings = ConnectionPoolSettings())
extends ConnectionPool(url, user, password, settings) {
import com.mchange.v2.c3p0._
private[this] val _dataSource = new ComboPooledDataSource
_dataSource.setJdbcUrl(url)
_dataSource.setUser(user)
_dataSource.setPassword(password)
_dataSource.setInitialPoolSize(settings.initialSize)
_dataSource.setMaxPoolSize(settings.maxSize);
_dataSource.setCheckoutTimeout(settings.connectionTimeoutMillis.toInt);
override def dataSource: DataSource = _dataSource
override def borrow(): Connection = dataSource.getConnection()
override def numActive: Int = _dataSource.getNumBusyConnections(user, password)
override def numIdle: Int = _dataSource.getNumIdleConnections(user, password)
override def maxActive: Int = _dataSource.getMaxPoolSize
override def maxIdle: Int = _dataSource.getMaxPoolSize
override def close(): Unit = _dataSource.close()
}
implicit val factory = C3P0ConnectionPoolFactory
ConnectionPool.add("xxxx", url, user, password)
Switching ConnectionPool Implementation by configuration
When a ConnectionPoolFactory
implementation is already in place, it can be configured for use. By default, ScalikeJDBC comes pre-configured with commons-dbcp ½ and bonecp. If you need to integrate a different ConnectionPoolFactory
, you can add it to the repository as follows:
scalikejdbc.ConnectionPoolFactoryRepository.add("name", YourConnectionPoolFactory)
Default: commons-dbcp2
https://commons.apache.org/proper/commons-dbcp/
https://search.maven.org/search?q=g:org.apache.commons%20AND%20a:commons-dbcp2
ConnectionPool.singleton(url, user, password,
ConnectionPoolSettings(connectionPoolFactoryName = "commons-dbcp2"))
commons-dbcp 1.x
Previously, commons-dbcp 1.4 served as the default connection pool for ScalikeJDBC. While it is no longer recommended, if there is a specific reason to use version 1.4, it can still be specified as commons-dbcp
in the configuration.
ConnectionPool.singleton(url, user, password,
ConnectionPoolSettings(connectionPoolFactoryName = "commons-dbcp"))
commons-dbcp
dependency should be added by yourself.
libraryDependencies += "commons-dbcp" % "commons-dbcp" % "1.4"
HikariCP
https://github.com/brettwooldridge/HikariCP
HikariCP expects dataSourceClassName. So we recommend using DataSourceConnectionPool.
val dataSource: DataSource = {
val ds = new HikariDataSource()
ds.setDataSourceClassName(dataSourceClassName)
ds.addDataSourceProperty("url", url)
ds.addDataSourceProperty("user", user)
ds.addDataSourceProperty("password", password)
ds
}
ConnectionPool.singleton(new DataSourceConnectionPool(dataSource))
HikariCP
dependency should be added by yourself.
libraryDependencies += "com.zaxxer" % "HikariCP" % "3.+"