首先是一些背景知识:我正在使用Spring Security的修改版本来执行Active Directory身份验证,并检查存储在数据库中的可能访问权限。这意味着在普通的Groovy类中调用从数据库加载信息:
if (Holders.config.loadRolesFromDatabase)
{
Set<DomainClassRole> roles = DomainClassUser.findByUsername(username)?.roles
if (roles)
authorities.addAll(roles.collect({ new SimpleGrantedAuthority('ROLE_' + it.name) }))
}
这对Hibernate 4.3.6.1和Tomcat 7.0.54起到了很好的作用,但是,在升级它们(到4.3.10.18和8.0.14.1)后,它现在生成一个“HibernateException:当前线程找不到会话”异常动态查找器方法。在做了一些研究之后,我决定将这段代码包装在withTransaction块中:
if (Holders.config.loadRolesFromDatabase)
{
DomainClassUser.withTransaction({
Set<DomainClassRole> roles = DomainClassUser.findByUsername(username)?.roles
if (roles)
authorities.addAll(roles.collect({ new SimpleGrantedAuthority('ROLE_' + it.name) }))
})
}
这解决了错误,但是,我不确定为什么这是必需的。我目前对withTransaction的理解是它用于创建可以在异常情况下回滚的事务等。但是,我不需要在这里执行任何回滚(它只是所有只读调用),为什么我仍然需要一个交易来执行此调用吗?
答案 0 :(得分:3)
有一种静态的withSession
方法看起来像是你需要的,但它不是;不幸的是,它只使当前的Hibernate会话可用,但如果没有活动/当前会话,它就不会创建一个。但withTransaction
确实如此,因为在Grails中使用Hibernate时,PlatformTransactionManager
是HibernateTransactionManager
,它确保在事务持续时间内存在活动会话,并在之前刷新并关闭它提交(除非有显式或自动(异常触发)回滚)。
因此,以这种方式使用withTransaction
会有点麻烦,因为您依赖于副作用,但无论如何您都要去数据库,所以事务开销(实际上只是对自动提交设置为false的连接的初始调用,隔离级别等,以及最后的无操作提交调用)很小,通常不是问题。我们真正需要的是withSession
和withTransaction
之间的某些内容,它使会话可用并在当前代码的持续时间内创建一个会话,但没有不必要的事务。
答案 1 :(得分:1)
This is why you need Transactions即使在阅读数据时也是如此。所有数据库语句都必须在物理事务中注册,因此它不像您不使用它们。如果您没有明确拥有事务边界,则只需在自动提交模式下进行调整,因此每个语句都在不同的数据库事务中运行(这会产生更多开销)。更不用说连接池解决方案的压力过大。
答案 2 :(得分:1)
您应该使用withNewSession()
。根据文档,它可以从史前Grails 1.2.0开始提供。
简短回顾:
withSession()
- 使当前的Hibernate会话可用(如果存在,否则你得到&#34;找不到当前线程的会话&#34;)withNewSession()
- 创建新的Hibernate会话而不启动事务(我相信最适合您的解决方案)withTransation()
- 启动并提交事务(不完全是简单只读操作的最佳选择)(在Grails 3.1.13上测试)