scala version: 2.12.7
scalikejdbc version: 4.0.0
HikariCP version: 4.0.3
近日使用scala开发flink与spark程序,遇到需要读写数据库的场景,因为手写jdbc太过繁琐,就找到了scalikejdbc的框架,该框架对jdbc进行了封装,支持scala的多种特性,也支持多数据源,用起来很方便。
但是因为其自带连接池是dbcp,性能不是太好,所以打算换成性能较高的HikariCP连接池,并进行多数据配置,写此文档进行记录。
有一点需要注意,使用第三方连接池需要配置closer参数,否则会出现数据库连接池关不掉的情况,产生大量数据库连接,造成资源泄露
首先引入scalikejdbc与HikariCP(5.0.0以上版本不支持jdk1.8)的依赖:
<dependency>
<groupId>org.scalikejdbc</groupId>
<artifactId>scalikejdbc_2.12</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>4.0.3</version>
</dependency>
配置单数据源
object ConfigDao {
private var init = false
def initDbPool(config: DbConfigDTO): Unit = {
if (!init) {
val dataSource: DataSource = {
val ds = new HikariDataSource()
ds.setJdbcUrl(config.url)
//这里需要写一下数据库对应的Driver,有时无法自动获取
ds.setDriverClassName("org.postgresql.Driver")
ds.setUsername(config.username)
ds.setPassword(config.password)
ds
}
ConnectionPool.singleton(new DataSourceConnectionPool(dataSource, closer = () => dataSource.close()))
LOG.info("初始化pg数据库连接池")
init = true
}
}
}
配置多数据源
object ConfigDao {
var initOracle: Boolean = false
var initMysql: Boolean = false
def initOracleDbPool(dbConfig: DbConfigDTO): Unit = {
if (!initOracle) {
val dataSource: DataSource = {
val ds = new HikariDataSource()
ds.setJdbcUrl(dbConfig.url)
ds.setDriverClassName("oracle.jdbc.driver.OracleDriver")
ds.setUsername(dbConfig.username)
ds.setPassword(dbConfig.password)
ds
}
//添加连接池的时候加上symbol参数,便于使用时通过NamedDB获取对应连接池
ConnectionPool.add('oracle, new DataSourceConnectionPool(dataSource, closer = () => dataSource.close()))
logger.info("初始化oracle数据库连接池")
initOracle = true
}
}
def initMysqlDbPool(dbConfig: DbConfigDTO): Unit = {
if (!initMysql) {
val dataSource: DataSource = {
val ds = new HikariDataSource()
ds.setJdbcUrl(dbConfig.url)
ds.setDriverClassName("com.mysql.cj.jdbc.Driver")
ds.setUsername(dbConfig.username)
ds.setPassword(dbConfig.password)
ds
}
//添加连接池的时候加上symbol参数,便于使用时通过NamedDB获取对应连接池
ConnectionPool.add('mysql, new DataSourceConnectionPool(dataSource))
logger.info("初始化mysql数据库连接池")
initMysql = true
}
}
}
然后需要使用数据库时先调用该方法初始化连接池:
单数据源使用方法
def getAreaInfo(dbConfig: DbConfigDTO): Map[String, (String, String, Int)] = {
initDbPool(dbConfig)
DB readOnly { implicit session =>
sql"select area_code, area_name, up_area_code, area_lev from dim_o_ias_n_area"
.fetchSize(500)
.map(rs => (rs.string("area_code"), (rs.string("area_name"), rs.string("up_area_code"), rs.int("area_lev"))))
.list
.apply
.toMap
}
}
多数据源使用方法
def getAreaInfo(dbConfig: DbConfigDTO): Map[String, (String, String, Int)] = {
initOracleDbPool(dbConfig)
//使用NamedDB,参数填初始化连接池时注册的对应symbol
NamedDB('oracle) readOnly { implicit session =>
sql"select area_code, area_name, up_area_code, area_lev from dim_o_ias_n_area"
.fetchSize(500)
.map(rs => (rs.string("area_code"), (rs.string("area_name"), rs.string("up_area_code"), rs.int("area_lev"))))
.list
.apply
.toMap
}
}