Hibernate 4无法为当前线程获取事务同步会话

Posted

技术标签:

【中文标题】Hibernate 4无法为当前线程获取事务同步会话【英文标题】:Hibernate 4 Could not obtain transaction-synchronized Session for current thread 【发布时间】:2015-04-11 13:33:39 【问题描述】:

我知道这不是一个新问题。例如,可以在here 找到很多有问题的和回复的收件人。但是,我没有设法解决我的问题。

我使用 Hibernate 4 + Spring 4 和 PostgreSQL。 我为整个班级标记了 DAO 和 DAOImpl @Transactional

package org.app.server.dao.impl;

@Repository
@Transactional
public class UserDAOImpl implements UserDAO 

  @Autowired
  private SessionFactory sessionFactory;

  public User getUser(String login) 
    User user =
            (User) sessionFactory.getCurrentSession().createQuery("from User p where p.login=:login")
                    .setParameter("login", login).uniqueResult();
    return user;
  

  @Override
  public void addUser(User user) 
    sessionFactory.getCurrentSession().save(user);
  

用户是一个@Entity

package org.app.model;

@Entity
@Table(name = "person")
public class User implements Serializable 
  private static final long serialVersionUID = 1L;

  public User() 
  

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(columnDefinition = "serial")
  private Integer id;

  @NotNull
  private String login;

  @NotNull
  private String password;

  private String email;

 // getters and setters

现在我从表单注册了一个用户。控制器捕获数据:

package org.app.controller;

@Controller
@Scope("prototype")
public class MyController 

@Autowired
private UserOperations userOperations;

  @ModelAttribute("user")
  public User getUserObject() 
    return new User();
  

  @RequestMapping(value="/newuser", method = RequestMethod.POST)
  public ModelAndView newUser(@ModelAttribute("user") User user, BindingResult result) 
    userOperations.signup(user);
    return new ModelAndView("redirect:/somepage");
  

并将其发送到 UserOperations @Component 以检查此类登录是否已经存在并插入新用户。显然,这必须在一笔交易中完成:

package org.app.server;

@Component
@Scope("prototype")
public class UserOperations 

  @Autowired
  private UserDAO userDAO;

  @Transactional
  public void signup(User user) 
    if (userDAO.getUser(user.getLogin()) == null) 
      userDAO.addUser(user);
        
  

所以当我运行它时,我有以下内容:

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.app.server.dao.impl.UserDAOImpl.getUser(UserDAOImpl.java:30)
    at org.app.server.UserOperations.signup(UserOperations.java:25)
    at org.app.controller.StartPageController.newUser(StartPageController.java:56)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

这是我的 xml 配置: applicationContext.xml

<context:component-scan base-package="org.app.server" />
<context:annotation-config />

<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource"
    p:driverClassName="$jdbc.driverClassName" p:url="$jdbc.databaseurl"
    p:username="$jdbc.username" p:password="$jdbc.password" />

<bean id="flyway" class="org.flywaydb.core.Flyway" init-method="migrate">
    <property name="dataSource" ref="dataSource"/>
</bean>

<bean id="sessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" depends-on="flyway">
    <property name="dataSource" ref="dataSource" />
    <property name="packagesToScan">
         <array>
              <value>org.app.server</value>
              <value>org.app.model</value>
         </array>
    </property> 
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.dialect">$jdbc.dialect</prop>
            <prop key="hibernate.connection.charSet">UTF-8</prop>
            <prop key="hibernate.hbm2ddl.auto">$jdbc.hbm2ddl</prop>
        </props>
    </property>
</bean>

springmvc-servlet.xml

<context:component-scan base-package="org.app.controller, org.app.server" />
<mvc:annotation-driven />
<mvc:default-servlet-handler />

一个更有趣的事情是,当我分别使用 getUser 和 addUser(注册)时,例如,直接从 Controller 中,它工作正常。

【问题讨论】:

你是StartPageController 中的UserOperation 中的@Autowiring 吗? Spring 没有用它的 AOP black majick 来包装 UserOperation 以进行事务管理。 &lt;tx:annotation-driven /&gt; 后处理器没有拾取它,或者你没有从 Spring 上下文中获取对象实例。 是的,我愿意。我明白。我已经更新了问题。 这可能是因为您的事务管理仅在应用程序上下文中,而不在 servlet 上下文中。也许您可以尝试将org.app.controller 包添加到applicationContext.xml&lt;context:component-scan base-package="org.app.server" /&gt; 标记。不确定,我对 Spring 和它的 XML 配置没有太多经验,但我认为值得一试。 如果你曾经解决过这个问题,请说出如何。我被困在同样的问题上,我还没有找到并尝试过任何工作。我几乎可以肯定这是一个配置问题,但不知道是什么。 我的问题,(可能与任何其他问题无关)是 dispath-servlet 上下文注释与休眠的注释重叠扫描。这似乎是问题的根源。使调度 servlet 仅扫描 @Controllers 似乎已修复它。 【参考方案1】:

您必须在通话前打开会话

User user = (User)sessionFactory.getCurrentSession().createQuery("from User p where p.login=:login").setParameter("login", login).uniqueResult();

所以你必须这样做:

Session session = sessionFactory.openSession();
User user = (User) session.createQuery("from User p where p.login=:login").setParameter("login", login).uniqueResult();

【讨论】:

每次打开会话都会影响性能,任何更好的解决方案和保存都不会一致【参考方案2】:

在 UserDao.getUser(String login) 方法之前添加 @transactional 注释应该可以解决这个问题。

【讨论】:

【参考方案3】:

在我的情况下,组件扫描特定包后没有 tx:annotation-driven。

【讨论】:

以上是关于Hibernate 4无法为当前线程获取事务同步会话的主要内容,如果未能解决你的问题,请参考以下文章

无法获取当前线程的事务同步会话

HibernateException:无法获取当前线程的事务同步会话。

无法使用“getcurrentsession”获取当前线程的事务同步会话,但使用“opensession”工作正常吗?

错误:无法使用 spring 任务执行器获取当前线程的事务同步会话

如何使用 JDBC 或 Hibernate 获取当前数据库事务 ID?

hibernate 的SessionFactory的getCurrentSession 与 openSession() 的区别