Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/265.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Hibernate sessionFactory.getCurrentSession()不带@Transactional_Java_Spring_Hibernate_Orm_Transactions - Fatal编程技术网

Java Hibernate sessionFactory.getCurrentSession()不带@Transactional

Java 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

在冬眠4,春天4
我想使用
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