Hibernate:如何改进会话和事务的处理?
我目前正在用Kotlin/ktor和Hibernate(没有Spring!)开发一个服务器应用程序,我对如何处理Hibernate会话和事务不太满意。因此,我正在寻找一些关于如何改进我的设置的建议,或者(如果合理的话)一些我正在做的事情实际上并没有那么糟糕的保证 所做的任何调用都将转发到处理程序函数,该函数在ktors路由功能中调用Hibernate:如何改进会话和事务的处理?,hibernate,kotlin,session,transactions,ktor,Hibernate,Kotlin,Session,Transactions,Ktor,我目前正在用Kotlin/ktor和Hibernate(没有Spring!)开发一个服务器应用程序,我对如何处理Hibernate会话和事务不太满意。因此,我正在寻找一些关于如何改进我的设置的建议,或者(如果合理的话)一些我正在做的事情实际上并没有那么糟糕的保证 所做的任何调用都将转发到处理程序函数,该函数在ktors路由功能中调用 route("foo"){ get { FooHandler.doStuff(call) } //...
route("foo"){
get {
FooHandler.doStuff(call)
}
//...
}
忽略处理请求和响应,这些函数(例如,doStuff()
)可能如下所示:
suspend fun doStuff(call: ApplicationCall) {
val session = HibernateDBA.sessionFactory.openSession()
session.beginTransaction()
SomeDAO(session).makeChanges(someObj)
SomeOtherDAO(session).makeChanges(someOtherObj)
session.transaction.commit()
session.close()
}
class SomeDAO (val session: Session = HibernateDBA.sessionFactory.openSession()) {
fun makeChanges(someObj : SomeClass, someOtherObj : SomeOtherClass) {
session.persist(someObj)
SomeOtherDAO(session).makeChanges(someOtherObj)
}
}
如您所见,我将会话传递给DAO的构造函数,因为makeChanges()
需要会话(例如,对于session.persist(someObj)
)。这里困扰我的是,我必须在每个处理函数中包含相同的4行代码
我还想指出,我有意在我的示例中包含多个DAO,因为这在我的应用程序中很常见,也是我努力寻找令人满意的解决方案的核心原因。如果这是愚蠢的,请随意指出,因为我仍在学习如何使用数据库和专门的休眠。如果是这样的话,我将非常感谢你给我的关于如何避免这种情况的建议
我最初的想法是拦截每个呼叫,在Routing.RoutingCallStarted
创建会话,然后在Routing.RoutingCallFinished
关闭会话。这将删除每个函数中的2行,但迫使我以某种方式管理调用
和会话
之间的关系(在映射或其他内容中),这对我来说似乎有些过分
另一种方法是在需要的地方链接我的DAO,在构造函数调用时打开会话,或者在需要时将现有会话传递给构造函数,这可能类似于:
suspend fun doStuff(call: ApplicationCall) {
val session = HibernateDBA.sessionFactory.openSession()
session.beginTransaction()
SomeDAO(session).makeChanges(someObj)
SomeOtherDAO(session).makeChanges(someOtherObj)
session.transaction.commit()
session.close()
}
class SomeDAO (val session: Session = HibernateDBA.sessionFactory.openSession()) {
fun makeChanges(someObj : SomeClass, someOtherObj : SomeOtherClass) {
session.persist(someObj)
SomeOtherDAO(session).makeChanges(someOtherObj)
}
}
DomeOtherDAO
将具有相同的布局,包括构造函数
然后我的处理程序只需调用SomeDAO().makeChanges(someObj,someOtherObj)
,而不是第二个块中的六行代码。听起来不错,但它不是:
- 现在我将someOtherObj传递给SomeDAO,这显然是不对的
- 我还没有解决交易处理问题。我没有忘记这一点,在这个例子中,我甚至不能想出一个伪解决方案。我必须知道,事务总是从
开始,并以SomeDAO.makeChanges()
SomeOtherDAO.makeChanges()结束
- 另外,在阅读这个想法的时候,我遇到了许多让我确信链接DAO通常是不好的做法的陈述
inline
函数,该函数接受任务(lamda),打开会话,执行给定任务,提交事务并关闭会话(注意suspend
关键字对于我的特定用例是必需的,对于一般方法不是必需的!)
第二:在处理函数中定义功能(例如doStuff()
),并将其传递给executeInSession()
:
编辑-一些评论:
- 在我的例子中,
和传递的doStuff()
需要task()
关键字,因为他们正在处理suspend
,它们是协同程序io.ktor.application.ApplicationCalls
- 在扩展中,
需要被executeInSession()
ed,因为 它内联了suspend
-函数suspend
- 在我的情况下,可能会有调用返回加载的信息
因此,为什么lambda-
任务和
函数返回executeInSession()
。你应该只通过吗 自包含任务,您可以从Any
并将lambda的返回类型更改为executeInSession()
Unit