java – 没有@Transactional的Hibernate sessionFactory.getCurrentSession()
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了java – 没有@Transactional的Hibernate sessionFactory.getCurrentSession(),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含8086字,纯文字阅读大概需要12分钟。
内容图文
![java – 没有@Transactional的Hibernate sessionFactory.getCurrentSession()](/upload/InfoBanner/zyjiaocheng/757/75d8b4eac6794124a5cfaeea731dd106.jpg)
在Hibernate4中,Spring4
我想使用不带@Transactional注释的sessionFactory.getCurrentSession().有什么办法吗?
解决方法:
简单的答案是:是的,当然你可以像SessionFactory.getCurrentSession()只是一个接口的方法,所以你可以编写自己的实现类,为你提供你喜欢的任何Session.
但是,这可能不是您正在寻找的答案.
我们一直在问自己一个类似的问题:为什么在使用Hibernate和Spring的事务管理时,我们必须将@Transactional添加到我们所有的方法中,甚至只需要SELECT数据,因此不需要在上下文中执行数据库事务?
答案并非如此简单,但让我们看一下所涉及的管道,看看我们是否能理解它.
首先,正如SO在其他地方所提到的,会话的想法从根本上与交易的想法有关.在Session界面的javadoc中有一个提示:
The lifecycle of a Session is bounded by the beginning and end of a logical transaction. (Long transactions might span several database transactions.)
并深入研究@Transactional类的javadoc,确认其目的是指示何时应在“事务上下文”中执行代码,这不一定是数据库事务的上下文.
这也解释了为什么Spring的@Transactional注释允许你设置属性readOnly = true,但稍后会更多.
回到Spring4和Hibernate4,当你调用sessionFactory.getCurrentSession()时,它实际上在SessionFactoryImpl中执行以下代码:
public Session getCurrentSession() throws HibernateException {
if ( currentSessionContext == null ) {
throw new HibernateException( "No CurrentSessionContext configured!" );
}
return currentSessionContext.currentSession();
}
所以它实际上是推迟到CurrentSessionContext的实现(除非你正在使用JTA而你可能不想打开Pandora的盒子)由SpringSessionContext类处理:
@Override
public Session currentSession() throws HibernateException {
Object value = TransactionSynchronizationManager.getResource(this.sessionFactory);
if (value instanceof Session) {
return (Session) value;
}
else if (value instanceof SessionHolder) {
SessionHolder sessionHolder = (SessionHolder) value;
Session session = sessionHolder.getSession();
if (!sessionHolder.isSynchronizedWithTransaction() &&
TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(
new SpringSessionSynchronization(sessionHolder, this.sessionFactory, false));
sessionHolder.setSynchronizedWithTransaction(true);
// Switch to FlushMode.AUTO, as we have to assume a thread-bound Session
// with FlushMode.MANUAL, which needs to allow flushing within the transaction.
FlushMode flushMode = session.getFlushMode();
if (flushMode.equals(FlushMode.MANUAL) &&
!TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
session.setFlushMode(FlushMode.AUTO);
sessionHolder.setPreviousFlushMode(flushMode);
}
}
return session;
}
if (this.transactionManager != null) {
try {
if (this.transactionManager.getStatus() == Status.STATUS_ACTIVE) {
Session session = this.jtaSessionContext.currentSession();
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(new SpringFlushSynchronization(session));
}
return session;
}
}
catch (SystemException ex) {
throw new HibernateException("JTA TransactionManager found but status check failed", ex);
}
}
if (TransactionSynchronizationManager.isSynchronizationActive()) {
Session session = this.sessionFactory.openSession();
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
session.setFlushMode(FlushMode.MANUAL);
}
SessionHolder sessionHolder = new SessionHolder(session);
TransactionSynchronizationManager.registerSynchronization(
new SpringSessionSynchronization(sessionHolder, this.sessionFactory, true));
TransactionSynchronizationManager.bindResource(this.sessionFactory, sessionHolder);
sessionHolder.setSynchronizedWithTransaction(true);
return session;
}
else {
throw new HibernateException("Could not obtain transaction-synchronized Session for current thread");
}
}
并解释了为什么你会看到异常:
Could not obtain transaction-synchronized Session for current thread
当您在未使用@Transactional注释的方法中调用sessionFactory.getCurrentSession()时,TransactionSynchronizationManager.isSynchronizationActive()返回false,因为没有@Transactional注释,切入点尚未执行,这将创建已同步的事务. (有关详细信息,请参阅org.springframework.transaction.interceptor.TransactionInterceptor.)
因此,这将我们带回到我们的用例,即当我们只想对数据库执行SELECT时,我们不希望调用PlatformTransactionManager及其数据库事务代码的开销.实现此目的的简单方法是不调用sessionFactory.getCurrentSession(),而是仅显式打开Session.例如,使用这个Spring托管代码:
public class MyHibernateService {
@Autowired
private SessionFactory sessionFactory;
protected Session transactionalSession() {
return sessionFactory.getCurrentSession();
}
protected Session readOnlySession() {
if(TransactionSynchronizationManager.isSynchronizationActive())
return transactionalSession();
Session session = this.sessionFactory.openSession();
session.setFlushMode(FlushMode.MANUAL);
return session;
}
public List<SalixUrl> activeUrls() {
return readOnlySession().createCriteria(SalixUrl.class)
.add(Restrictions.gt("published", LocalDateTime.now()))
.add(Restrictions.lt("removed", LocalDateTime.now()))
.list();
}
@Transactional
public List<SalixUrl> refreshUrls() {
List<SalixUrl> urls = activeUrls();
for(SalixUrl url : urls) {
url.setLastChecked(LocalDateTime.now());
transactionalSession().update(url);
}
}
}
这将允许您在没有@Transactional注释的情况下调用myHibernateService.activeUrls(),还可以调用myHibernateService.refreshUrls(),而您需要通过PlatformTransactionManager.
如果这段代码看起来很熟悉,那可能是因为你已经查看了OpenSessionInViewFilter(或拦截器)的源代码,它通常用于缓解LazyLoadingExceptions,并且当程序员认为他们正在优化他们时,也会导致很多n 1问题. ORM模型使用FetchType.LAZY来定义实体关系,但尚未对其Service / Repository层进行编码,以实际获取需要为要生成的View获取的内容.
无论如何,您不想使用上面的代码.相反,您可能希望使用@Transactional注释,让Spring和Hibernate框架决定实际需要什么类型的数据库事务.
如果您担心性能,那么您有几个选择:
没有1.您可以使用Spring的@Transactional(readOnly = true),但请注意,这不一定是个好主意.我并不主张使用javax @Transactional,因为它更通用 – 如果你把你的颜色绑在Spring桅杆上,那么你也可以使用它提供的东西.相反,我很谨慎,因为它所做的一切(使用当前实现)是请求将来自底层数据库提供程序的Connection对象标记为只读.由于几个原因,这可能是有问题的.
首先,您的数据库提供程序可能不支持只读连接(例如,MSSQL服务器的jTDS JDBC驱动程序),因此它可能毫无意义.
第二个原因是由于连接池.如果您使用的是支持只读连接的数据库(如PostgreSQL)和连接池(如C3P0),那么您实际上并不想将某些连接标记为只读,然后将它们返回到池中,然后允许在需要执行数据库写入的方案中提供它们. (我没有用Hibernate4和Spring4测试过这个,但它确实是Spring3,Hibernate3和C3P0的问题.)
2.使用缓存.使用我们现在可以访问的硬件,缓存可能就是答案,您可以使用很多选项.您可以为Hibernate实体配置二级缓存,Spring本身有一个很好的spring-cache模块,允许缓存服务/存储库方法 – 看看如何集成EhCache.
3.使用JDBC或其他任何内容编写您自己的数据库查询. Gavin King(Hibernate作者)已经指出了很长一段时间,因为你使用Hibernate进行ORM,你不必将它用于所有事情:https://plus.google.com/+GavinKing/posts/LGJU1NorAvY(我找不到明确的引用,他说“不要”使用Hibernate进行高性能SELECT“但我想我几年前读过一些东西”.
但还有两个更重要的问题:
没有1.你不应该担心表现.如果你需要那么你不应该读这个,因为你应该已经知道了所有这些;-) – 但是忽略了我的讽刺,不要浪费时间进行原子代码优化,而是你需要像工程师一样行事在整个系统中(如Dirk Gently),然后判断最有效的方法,使您的系统尽可能高效.请记住:为什么协和会不再飞行有几个原因.
否2.您可能不再需要使用SessionFactory. JPA 2和EntityManager旨在使SessionFactory的显式使用变得不必要.甚至Emmanuel Bernard(另一位Hibernate作者)几年前给了我们这个建议:http://www.theserverside.com/news/2240186700/The-JPA-20-EntityManager-vs-the-Hibernate-Session-Which-one-to-use
但是你知道:我喜欢SessionFactory和Hibernate Criteria API以及随之而来的一切.所以我会继续使用它,直到他们从Spring框架中弃用对它的支持.因为,正如我所说的,如果你已经将颜色钉在框架桅杆上,那么你也可以使用框架所提供的所有功能.实际上,抽象的主要好处(你可以换掉底层的ORM或数据库提供者)是你可能永远不必担心的.
(但是,是的,我也去过那里也做过 – 我不得不将中型代码库从MSSQL迁移到PostgreSQL,最大的问题不是Spring / ORM层,而是数据库特定的代码,如存储过程和触发器.事实上以前的开发人员试图通过使用@Transactional(readOnly = true)来优化查询而不了解MSSQL实际上不支持它并且当你使用PostgreSQL和C3P0时它会中断.是的,我是仍然对此感到痛苦.)
内容总结
以上是互联网集市为您收集整理的java – 没有@Transactional的Hibernate sessionFactory.getCurrentSession()全部内容,希望文章能够帮你解决java – 没有@Transactional的Hibernate sessionFactory.getCurrentSession()所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。