Base on this answer, here is Kotlin/Spring code to get an enum value depending on some known values for the databaseProductName
:
@Component
class DbDetector {
@Autowired
private lateinit var dataSource: DataSource
val dbType by lazy { detectDatabase() }
private fun detectDatabase(): DbType {
val rawName = dataSource.connection.use {
it.metaData.databaseProductName
}
return when (rawName) {
"MySQL" -> DbType.MY_SQL
"Oracle" -> DbType.ORACLE
"PostgreSQL" -> DbType.POSTGRES
"Microsoft SQL Server" -> DbType.SQL_SERVER
"HSQL Database Engine" -> DbType.HSQLDB
"H2" -> DbType.H2
else -> DbType.UNKNOWN
}
}
}
enum class DbType {
MY_SQL, ORACLE, POSTGRES, SQL_SERVER, HSQLDB, H2, UNKNOWN
}
NB: Closing the Datasource & Connection Leaks
One critical thing that caused me pain and I wanted to point out explicitly was the closing of the database connection after use. Kotlin's use
construct elegantly allows this:
val rawName = dataSource.connection.use {
it.metaData.databaseProductName
}
Below is previous, buggy code that I had which wasn't closing the connection afterwards. I've crossed it out to make it obvious that you shouldn't use it, because it might not obviously fail on first use and you may think it's OK:
val rawName = dataSource.connection.metaData.databaseProductName
For me, there were no apparent errors with this code for a while. But it was causing a subtle connection leak, which was only detected luckily when my connection pool maxed out during a test and a connection started to timeout. This answer then pointed me towards debugging the timeout with a leak detection setting in application.properties
:
spring.datasource.hikari.leakDetectionThreshold=2000