【问题标题】:Transaction management for starter bean in Spring 4 + HibernateSpring 4 + Hibernate中starter bean的事务管理
【发布时间】:2016-07-25 02:56:49
【问题描述】:

在我的 Spring MVC + Hibernate 应用程序中,我有 XML 配置的启动 bean:

<bean name="starter" init-method="create" class="foo.CreateDefaultUserBean" lazy-init="false"/>

我还配置了事务管理:

<tx:annotation-driven transaction-manager="txManager"/>

<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

CreateDefaultUserBean 已自动连接SessionFactory

public class CreateDefaultUserBean {

    @Autowired
    private SessionFactory sessionFactory;

    @Transactional
    public void create() {
        User adminUser = (User) sessionFactory.getCurrentSession().createCriteria(User.class).add(Restrictions.eq("login", username)).uniqueResult();
         // ...
    }
}

所以它因Could not obtain transaction-synchronized Session for current thread 异常而失败:

 org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'starter' defined in ServletContext resource [/WEB-INF/app-servlet.xml]: Invocation of init method failed; nested exception is org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1578)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
    at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:667)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:633)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:681)
    at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:552)
    at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:493)
    at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
    at javax.servlet.GenericServlet.init(GenericServlet.java:158)
    at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1238)
    at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1151)
    at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:828)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:135)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1502)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1458)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
    at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:134)
    at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1014)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1502)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1458)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

我做错了什么?

【问题讨论】:

  • 无法保证在调用 init 方法时已经创建了事务代理。因此,在 init 方法中进行事务性工作通常不会像 stackoverflow.com/questions/17346679/… 中解释的那样工作。您必须使用TransactionTemplate 或自己使用PlatformTransactionManager 来管理交易。

标签: java spring hibernate spring-mvc transactions


【解决方案1】:

作为解决方法,我发现我可以只使用openSession() 而不是使用currentSession()

Session session = sessionFactory.openSession();

这种情况下@Transactional注解也是没用的。这并不能解释为什么在所描述的配置中会出现Could not obtain transaction-synchronized Session for current thread 异常,但有助于获得所需的结果。

【讨论】:

  • 但是使用 Spring 事务管理的重点不就是避免创建和销毁会话吗?
  • @praveen 我同意,所以这是我的问题。 Gab表示这种情况下可以使用。
  • @Andremonly 你能看看这个stackoverflow.com/questions/26562787/… 你的堆栈跟踪中也没有 TransactionInterceptor..
【解决方案2】:
  • 当前会话是使用@Transactionnal 注释方法上应用的专用方面创建并绑定到当前线程的。
  • Spring 方面使用 JDK/cglib 动态代理
  • 动态代理与被代理对象具有相同的契约并封装它。当 Spring 注入一个 bean 时,它会注入代理来代替原始对象

因此 Spring 构建您的 bean(使用默认构造函数和最终的 init 方法)然后将其封装在代理中并注入代理来代替 bean。直接调用 init 方法,不应用事务方面;此时没有任何当前会话或事务可用。

与此处@Transactional on @PostConstruct method 相同的问题和解决方法

【讨论】:

  • 感谢您的解释。那么,我在此处发布的解决方法是否正确?
  • 您的解决方法创建了一个会话并将其绑定到当前线程,但仍没有应用事务方面(忽略事务注释)。
  • @Gab 那么该问题的解决方法是什么?
  • 直接注入txManager并手动(或使用spring TransactionTemplate)进行事务处理。
  • @Gab 和 session.beginTransaction() 和手动 commitrollback 呢?
猜你喜欢
  • 2013-01-27
  • 2012-10-16
  • 2016-12-02
  • 2013-07-22
  • 1970-01-01
  • 1970-01-01
  • 2012-05-06
  • 2011-07-05
  • 1970-01-01
相关资源
最近更新 更多