我正在尝试创建一个非常简单的事务管理器,如下所示:
object PersistenceManager {
private val dataSource: DataSource by lazy {
val config = ConfigFactory.load()
hikari(config.getConfig("postgres"))
}
private fun hikari(appConfig: Config): DataSource {
// init datasource
}
fun <T> transaction(statement: Connection.() -> T): T {
val connection = dataSource.connection
try {
return connection.statement()
} catch (e: Exception) {
connection.rollback()
throw e
} finally {
connection?.close()
}
}
}
class BrandsDB {
private val query = "select name from brands order by name"
fun Connection.getAll(): List<String> {
val ps = this.prepareStatement(query)
val rs = ps.executeQuery()
return JdbcMapperFactory.newInstance()
.newMapper(String::class.java)!!.stream(rs).toList()
}
}
class BrandsService(private val brandsDB: BrandsDB) {
fun getBrands(): List<String> {
return transaction {
brandsDB.getAll() // I'd like to do something like this but since
// getAll() method belongs to Connecion, I can't
}
}
}
因此,所有这些操作背后的想法是,我可以在一个transaction
块中包含多个查询,如果出现任何问题,可以回滚(应该在那些查询中插入或更新)。我也想避免将连接传递给brandsDB.getAll()
方法,但是让它以“隐式”方式获取连接。
我知道我可以将getAll()
方法提取到其自己的文件中或使BrandsDB
类成为对象,但这将使在任何地方以静态方式调用该方法成为可能,而我没有这样做。喜欢。我也不想将任何与数据库相关的代码放在BrandsService
中,只有业务逻辑应该放在那里。
这可能吗?
答案 0 :(得分:1)
Connection
是Java中的一个接口(不是类!),因此您可以创建自己的接口以对其进行扩展并委托给它。
interface OurConnection : Connection {
fun getAll() : SomeType
}
fun <T> PersistenceManager.extendedTransaction(action: OurConnection.() -> T) : T {
//call the original method
return PersistenceManager.transaction {
object : OurConnection, Connection by this {
override fun getAll() = TODO("implement me")
}.action()
}
}
我使用委托的实现在接口中隐式委托Connection
方法。这是Connection by this
行,其中this
是来自PersistenceManager.transaction
函数调用的lambda接收器对象。