Spring @transactional与hibernate问题-没有活动事务无效



前言-使用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框架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>

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

要启用@Transactional,必须使用@EnableTransactionManagement,或者在使用XML配置的情况下添加<tx:annotation-driven/>。它基本上为您做了以下工作(来源):

@EnableTransactionManagement and是负责注册所需的Spring组件注释驱动的事务管理,例如TransactionInterceptor和基于代理或aspectj的建议将拦截器编织到调用堆栈中,当JdbcFooRepository@事务性方法被调用

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

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

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方法在删除这些"仪式"之后会变得非常干净。代码。

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

最新更新