Java Hibernate sessionFactory.getCurrentSession()不带@Transactional
在冬眠4,春天4Java Hibernate sessionFactory.getCurrentSession()不带@Transactional,java,spring,hibernate,orm,transactions,Java,Spring,Hibernate,Orm,Transactions,在冬眠4,春天4 我想使用sessionFactory.getCurrentSession()而不使用@Transactional注释。有什么方法可以做到这一点吗?您可以使用Hibernate而不声明,但您只能发出SELECT语句,因为DML语句需要事务 使用注释是实现声明式事务管理的一种方法,但不是唯一的方法。您也可以在xml配置中使用tx和aop名称空间。这样,您就有了一个集中式事务配置,在该配置中还可以使用通配符进行方法匹配。 您可以用同样的方法使用sessionFactory.getCu
我想使用
sessionFactory.getCurrentSession()
而不使用@Transactional
注释。有什么方法可以做到这一点吗?您可以使用Hibernate而不声明,但您只能发出SELECT语句,因为DML语句需要事务 使用注释是实现声明式事务管理的一种方法,但不是唯一的方法。您也可以在xml配置中使用tx
和aop
名称空间。这样,您就有了一个集中式事务配置,在该配置中还可以使用通配符进行方法匹配。
您可以用同样的方法使用sessionFactory.getCurrentSession()。只有事务划分样式发生了变化
有关更多详细信息,请参阅。简单的答案是:是,当然可以作为
会话工厂。getCurrentSession()
只是一种接口方法,因此您可以编写自己的实现类,为您提供所需的会话
然而,这可能不是你想要的答案
我们一直在问自己一个类似的问题:为什么在使用Hibernate和Spring的事务管理时,我们必须将@Transactional
添加到我们的所有方法中,即使是那些只选择
数据,因此不需要在数据库事务上下文中执行的方法
这个问题的答案并不简单,但让我们看看其中涉及的一些管道,看看我们是否能理解它
首先,正如前面提到的,会话
的概念从根本上与事务的概念相联系。javadoc中有一个关于会话
接口的提示:
会话的生命周期以逻辑事务的开始和结束为界限。(长事务可能跨越多个数据库事务。)
深入研究@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
的实现,而SpringSessionContext
类处理该实现(除非您使用的是JTA,并且您可能不想打开潘多拉的盒子):
@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");
}
}
并解释了您将看到异常的原因:
无法获取当前线程的事务同步会话
在方法中调用sessionFactory.getCurrentSession()
时,该方法未使用@Transactional
注释为TransactionSynchronizationManager.isSynchronizationActive()
返回false
,因为如果没有@Transactional
注释,切入点就不会执行,这将创建一个同步事务。(更多信息请参见org.springframework.transaction.interceptor.TransactionInterceptor
)
因此,这就引出了我们的用例,即当我们只想对数据库执行SELECT
时,我们不需要调用PlatformTransactionManager
及其数据库事务代码的开销。实现这一点的简单方法是不调用sessionFactory.getCurrentSession()
,而是显式地打开一个会话。例如,以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);
}
}
}
公共类MyHibernateService{
@自动连线
私人会话工厂会话工厂;
受保护的会话transactionalSession(){
返回sessionFactory.getCurrentSession();
}
受保护的会话只读会话(){
if(TransactionSynchronizationManager.isSynchronizationActive())
返回transactionalSession();
Session Session=this.sessionFactory.openSession();
session.setFlushMode(FlushMode.MANUAL);
返回会议;
}
公共列表ActiveURL(){
return readOnlySession().createCriteria(SalixUrl.class)
.add(Restrictions.gt(“published”,LocalDateTime.now()))
.add(Restrictions.lt(“已删除”,LocalDateTime.now()))
.list();
}
@交易的
公共列表刷新URL(){
列表URL=ActiveURL();
用于(SalixUrl:url){
setLastChecked(LocalDateTime.now());
transactionalSession().update(url);
}
}
}
这将允许您调用myHibernateService.activeUrls()
,而无需@Transactional
注释,还可以调用myHibernateService.refreshUrls()
,您希望通过平台TransactionManager
查看这些注释
如果这段代码看起来非常熟悉,可能是因为您已经查看了OpenSessionInViewFilter
(或拦截器)的源代码这通常用于缓解LazyLoadingException
s,当程序员认为他们正在通过使用FetchType.LAZY
定义实体关系来优化ORM模型时,它也会导致许多n+1问题,但还没有对其服务/存储库层进行编码以实际获取需要获取的数据要生成的视图
在任何情况下,您都不想使用上述代码。相反,您可能希望使用@Transactional
注释,让Spring和Hibernate框架决定实际需要什么类型的数据库事务
如果你担心per