【问题标题】:Spring @transactional with hibernate issue - not valid without an active transaction带有休眠问题的 Spring @transactional - 如果没有活动事务则无效
【发布时间】:2021-12-09 07:23:36
【问题描述】:

序言 - 使用 Spring

我对 spring @Transactional 注释的目的感到困惑。我从我读过的几篇博文中想到,它可以让我简化事务管理并只写这个,它会自动处理连接/提交/回滚:

public class DaoImpl implements Dao {
   @Autowired
   private SessionFactory sessionFactory;

    @Transactional
    public void saveOrUpdateOne(final AdditionalDataItem item) {
        Session session = sessionFactory.getCurrentSession();
            session.saveOrUpdate(p_item);
    }
}

但这给了我一个例外:“调用方法'saveOrUpdate'在没有活动事务的情况下无效”

如果我改为将保存方法更改为此,一切正常 - 所以我的问题是,@Transactional 在做什么?

@Override
@Transactional
public void saveOrUpdateOne(final AdditionalDataItem p_item) {
    Session session = null;
    Transaction trans = null;
    try {
        session = sessionFactory.getCurrentSession();
        trans = session.beginTransaction();
        TransactionStatus status = trans.getStatus();
        session.saveOrUpdate(p_item);
        trans.commit();
    } catch (Exception e) {
        LOGGER.error("Exception saving data: {}", e.getMessage());
        if (trans != null) {
            try {
                trans.rollback();
            } catch (RuntimeException rbe) {
                LOGGER.error("Couldn’t roll back transaction", rbe);
            }
        }
    } finally {
        if (session != null && session.isOpen()) {
            try {
                session.close();
            } catch (HibernateException ne) {
                LOGGER.error("Couldn’t close session", ne);
            }
        }
    }
}

作为参考,我将 Java 11 与 Spring Framework 5.3.7 和 hibernate 5.5.7 一起使用,并具有适当的 dao、会话工厂和 tx 管理器 bean:

    <bean id="sessionFactory" 
      class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
    <property name="dataSource" ref="${sessionFactory.datasource}" />
    <property name="configLocation" value="${sessionFactory.configLocation}" />
</bean>

<bean id="txManager" 
  class="org.springframework.orm.hibernate5.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="Dao" class="com.xxxxx.dao.DaoImpl">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

【问题讨论】:

  • 你的daoimpl是spring组件吗?
  • 是的,我已经编辑了问题以显示正在定义的 DAO bean。我也尝试将@Service 添加到 bean 但得到相同的结果。
  • 你从哪里调用 saveOrUpdateOne?
  • 您的 xml 中是否有 ,或者在某些 @Configuration 类中有注释 EnableTransactionManagement?

标签: java spring hibernate transactions


【解决方案1】:

这是因为您还没有启用@Transactional 并且在调用session.saveOrUpdate() 时也没有开始事务,所以它会给您错误“没有活动的事务无效”。

要启用@Transactional,您必须使用@EnableTransactionManagement 或添加&lt;tx:annotation-driven/&gt;,以防您使用XML 配置。它基本上为您执行以下操作(source):

@EnableTransactionManagement 和 是 负责注册必要的 Spring 组件 注释驱动的事务管理,例如 TransactionInterceptor 和基于代理或 AspectJ 的建议 当 JdbcFooRepository's 时将拦截器编织到调用堆栈中 @Transactional 方法被调用。

您的工作示例有效,因为您自己手动管理事务。这与 @Transactional 无关,因为您从未启用它。

以工作代码为例,@Transactional 为您做的就是您不再需要手动编写以下事务代码,它们都将封装在TransactionInterceptor 中并围绕您的@Transactional 执行基于AOP的方法:

public Object invoke() {
    Session session = null;
    Transaction trans = null;
    try {
        session = sessionFactory.getCurrentSession();
        trans = session.beginTransaction();
        TransactionStatus status = trans.getStatus();
             
        /***********************************************/
         Here it will invoke your @Transactional Method
        /************************************************/

        trans.commit();
    } catch (Exception e) {
        LOGGER.error("Exception saving data: {}", e.getMessage());
        if (trans != null) {
            try {
                trans.rollback();
            } catch (RuntimeException rbe) {
                LOGGER.error("Couldn’t roll back transaction", rbe);
            }
        }
    } finally {
        if (session != null && session.isOpen()) {
            try {
                session.close();
            } catch (HibernateException ne) {
                LOGGER.error("Couldn’t close session", ne);
            }
        }
    }
}

所以你可以看到你的@Transactional方法在去掉这些“仪式”代码后会变得非常干净。

【讨论】:

    【解决方案2】:

    @Transactional 用于如果您想更新 2 个表,如果其中一个失败,另一个将自动回滚 你可以使用上面的方法 您可以使用 Repository 类的 bean 调用保存或更新

    【讨论】:

      猜你喜欢
      • 2018-12-31
      • 1970-01-01
      • 2016-05-19
      • 2015-10-19
      • 1970-01-01
      • 2015-06-23
      • 1970-01-01
      • 2011-11-16
      • 2013-12-16
      相关资源
      最近更新 更多