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作为主要框架):

    道:
    @Repository
    public class UrlDaoImpl implements UrlDao {
    
        @Autowired
        private SessionFactory sessionFactory;
    
        @Override
        public List<Url> getAllUrls() {
            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 List<Url> getAllUrls() {
            return urlDao.getAllUrls();
        }
    
        @Override
        @Transactional(propagation = Propagation.NOT_SUPPORTED)  // THIS USED TO WORK BUT NOW THROWS EXCEPTION
        public List<Url> 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";
        }
    
    }
    

    新的Hibernate中的Stacktrace异常:
    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)
    

    最佳答案

    好的,经过几个小时的尝试不同的配置(将此问题发布到SO之前),我终于找到了解决方案。

    对于新的Hibernate版本,如果要执行没有事务的方法,则必须在@Transactional上声明另一个必需的参数:readOnly = true。因此,服务部分的工作示例是:

    @Service
    public class UrlServiceImpl implements UrlService {
    
        @Autowired
        private UrlDao urlDao;
    
    
        @Override
        @Transactional
        public List<Url> getAllUrls() {
            return urlDao.getAllUrls();
        }
    
        @Override
        @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)  // ADDED READONLY TO WORK IN NEW HIBERNATE VERSIONS
        public List<Url> getAllUrlsNoTxn() {
            return urlDao.getAllUrls();
        }
    
    }
    

    我还通过调用((org.hibernate.engine.transaction.internal.TransactionImpl) session.getTransaction()).isActive();来确认它在调试中是否有效,该命令返回第一个Service方法(带有事务)的true和第二个Service方法(带有Propagation.NOT_SUPPORTED)的false

    07-28 03:37
    查看更多