TL; DR:
用注释的服务方法 @Transactional(propagation = Propagation.NOT_SUPPORTED)
Hibernate 5.0.4.Final:一切都按预期工作(方法在没有事务的情况下执行)
Hibernate 5.2.5.Final:javax.persistence.TransactionRequiredException: no transaction is in progress
被抛出
作为这个问题的测试用例,我创建了一个简单的maven Web应用程序,并且代码中唯一的更改(来自旧工作项目的复制粘贴)是pom.xml中的Hibernate版本
题:
现在如何在没有交易的情况下执行服务方法的正确方法是什么?
代码片段(Spring用作主框架):
DAO:
@Repository public class UrlDaoImpl implements UrlDao { @Autowired private SessionFactory sessionFactory; @Override public ListgetAllUrls() { Session session = sessionFactory.getCurrentSession(); Query query = session.createQuery("from Url"); return query.list(); } }
服务:
@Service public class UrlServiceImpl implements UrlService { @Autowired private UrlDao urlDao; @Override @Transactional // THIS WORKS IN NEW HIBERNATE public ListgetAllUrls() { return urlDao.getAllUrls(); } @Override @Transactional(propagation = Propagation.NOT_SUPPORTED) // THIS USED TO WORK BUT NOW THROWS EXCEPTION public List getAllUrlsNoTxn() { return urlDao.getAllUrls(); } }
控制器:
@Controller public class HomeController { @Autowired private UrlService urlService; @RequestMapping(value = "/", method = RequestMethod.GET, produces = "text/plain") public String entryPoint() { urlService.getAllUrls(); System.out.println("--------------------- ok"); return "ok"; } @RequestMapping(value = "/no-txn", method = RequestMethod.GET, produces = "text/plain") public String entryPointNoTxn() { // EXCEPTION WILL BE THROWN BELOW urlService.getAllUrlsNoTxn(); System.out.println("--------------------- ok no txn"); return "ok no txn"; } }
Stacktrace用于新Hibernate中的异常:
exception org.springframework.web.util.NestedServletException: Request processing failed; nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982) org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) javax.servlet.http.HttpServlet.service(HttpServlet.java:622) org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) javax.servlet.http.HttpServlet.service(HttpServlet.java:729) org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) root cause javax.persistence.TransactionRequiredException: no transaction is in progress org.hibernate.internal.SessionImpl.checkTransactionNeeded(SessionImpl.java:3439) org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1410) org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1406) org.springframework.orm.hibernate5.SessionFactoryUtils.flush(SessionFactoryUtils.java:144) org.springframework.orm.hibernate5.SpringSessionSynchronization.beforeCommit(SpringSessionSynchronization.java:95) org.springframework.transaction.support.TransactionSynchronizationUtils.triggerBeforeCommit(TransactionSynchronizationUtils.java:95) org.springframework.transaction.support.AbstractPlatformTransactionManager.triggerBeforeCommit(AbstractPlatformTransactionManager.java:932) org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:744) org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730) org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:504) org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:292) org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) com.sun.proxy.$Proxy32.getAllUrlsNT(Unknown Source) com.example.web.controller.HomeController.entryPointNoTxn(HomeController.java:31) sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) java.lang.reflect.Method.invoke(Method.java:498) org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:220) org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:134) org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:116) org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963) org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897) org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) javax.servlet.http.HttpServlet.service(HttpServlet.java:622) org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) javax.servlet.http.HttpServlet.service(HttpServlet.java:729) org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
dominik.. 5
好的,经过几个小时尝试不同的配置(在将此问题发布到SO之前),我终于找到了解决方案.
对于新的Hibernate版本,@Transactional
如果要在没有事务的情况下执行方法,则必须声明另一个必需参数:readOnly = true
.因此,服务部分的工作示例是:
@Service public class UrlServiceImpl implements UrlService { @Autowired private UrlDao urlDao; @Override @Transactional public ListgetAllUrls() { return urlDao.getAllUrls(); } @Override @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED) // ADDED READONLY TO WORK IN NEW HIBERNATE VERSIONS public List getAllUrlsNoTxn() { return urlDao.getAllUrls(); } }
我还确认这可以通过调用第一个Service方法(带事务)和第二个Service方法(带Propagation.NOT_SUPPORTED)的((org.hibernate.engine.transaction.internal.TransactionImpl) session.getTransaction()).isActive();
返回true
来进行调试false
.
好的,经过几个小时尝试不同的配置(在将此问题发布到SO之前),我终于找到了解决方案.
对于新的Hibernate版本,@Transactional
如果要在没有事务的情况下执行方法,则必须声明另一个必需参数:readOnly = true
.因此,服务部分的工作示例是:
@Service public class UrlServiceImpl implements UrlService { @Autowired private UrlDao urlDao; @Override @Transactional public ListgetAllUrls() { return urlDao.getAllUrls(); } @Override @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED) // ADDED READONLY TO WORK IN NEW HIBERNATE VERSIONS public List getAllUrlsNoTxn() { return urlDao.getAllUrls(); } }
我还确认这可以通过调用第一个Service方法(带事务)和第二个Service方法(带Propagation.NOT_SUPPORTED)的((org.hibernate.engine.transaction.internal.TransactionImpl) session.getTransaction()).isActive();
返回true
来进行调试false
.