注释@Transactional。如何回滚?


90

我已成功将此注释用于Dao类。回滚适用于测试。

但是现在我需要回滚真实代码,而不仅仅是测试。有用于测试的特殊注释。但是哪些注释适用于非测试代码?对我来说这是一个大问题。我已经花了一天的时间。官方文档不符合我的需求。

class MyClass { // this does not make rollback! And record appears in DB.
        EmployeeDaoInterface employeeDao;

        public MyClass() {
            ApplicationContext context = new ClassPathXmlApplicationContext(
                    new String[] { "HibernateDaoBeans.xml" });
            employeeDao = (IEmployeeDao) context.getBean("employeeDao");
         }

        @Transactional(rollbackFor={Exception.class})
    public void doInsert( Employee newEmp ) throws Exception {
        employeeDao.insertEmployee(newEmp);
        throw new RuntimeException();
    }
}

员工道是

@Transactional
public class EmployeeDao implements IEmployeeDao {
    private SessionFactory sessionFactory;

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public void insertEmployee(Employee emp) {
        sessionFactory.getCurrentSession().save(emp);
    }
}

这是一个注释可以很好地运行的测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/HibernateDaoBeans.xml" })
@TransactionConfiguration(transactionManager = "txManager", defaultRollback = true)
@Transactional
public class EmployeeDaoTest {

    @Autowired
    EmployeeDaoInterface empDao;

    @Test
    public void insert_record() {
       ...
       assertTrue(empDao.insertEmployee(newEmp));
    }

HibernateDaoBeans.xml

   ...
<bean id="employeeDao" class="Hibernate.EmployeeDao">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>
    <tx:annotation-driven transaction-manager="txManager"/>

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



**是的,我回滚了交易。我刚刚为服务添加了BEAN ...,然后注释@Transactional开始起作用:-) **

<bean id="service" class="main.MyClass">
    <property name="employeeDao" ref="employeeDao" />
</bean>

谢谢大家,俄罗斯不会忘记您!

Answers:


159

只需RuntimeException从标记为的方法中抛出任何内容即可@Transactional

默认情况下,所有RuntimeExceptions都回滚事务,而检查的异常则不。这是EJB的遗留物。您可以使用rollbackFor()noRollbackFor()注释参数进行配置:

@Transactional(rollbackFor=Exception.class)

抛出任何异常后,这将回滚事务。


1
我尝试过这个。这是行不通的!我讲的不是直接在Dao对象中进行回滚操作,那可能会起作用。我介绍了另一个使用@Transactional的Dao方法的调用序列的对象。然后,我尝试为我的班级添加称为“ Dao”的注释。但这在这里不起作用。
莫斯科男孩

5
它确实以这种方式工作:-)。如果您有一个调用多个DAO的服务,则该服务也需要具有@Transactional注释。否则,在您在服务中引发异常之前,每个DAO调用都会启动并提交新事务。最重要的是:异常必须离开(转义)标记为的方法@Transactional
Tomasz Nurkiewicz

查看第一篇文章中添加的代码。我有一部分代码。执行后,我在数据库中有记录。=>回滚尚不起作用。
莫斯科男孩

从DAO抛出异常是否也不会回滚事务?您是否已org.springframework.orm.hibernate3.HibernateTransactionManager在Spring上下文中进行配置?如果启用org.springframework.transaction记录器,它显示任何有趣的东西吗?
Tomasz Nurkiewicz

1
如果您使用的是Spring Boot并允许其自动配置数据源,它将使用HikariDataSource,其默认情况下自动提交设置为true。您需要将其设置为false:hikariDataSource.setAutoCommit(false);。在配置DataSourceTransactionManager bean时,我在@Configuration类中进行了更改。
Alex

82

或以编程方式

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

12
是。因为有时您需要回滚而不会引发错误。
埃里卡·凯恩

2
你是救星。
墙壁

这是调用回滚imo的一种更合适的方法,理想情况下,您不希望为已知或受控条件引发异常。
jalpino

2
有时它不起作用。例如,就我而言,我有一个事务服务和非事务存储库。我从服务调用存储库,因此,它应该参与服务打开的事务。但是,如果我从非事务性存储库中调用您的代码,尽管存在事务,但它仍会引发NoTransactionException。
Victor Dombrovsky '18

3
您要在“非事务性存储库”中回滚哪个事务?
Stefan K.

5

您可以从要回滚的方法中引发未经检查的异常。春季将检测到这一点,并且您的交易记录将仅标记为回滚。

我假设您在这里使用Spring。我假设您在测试中引用的注释是基于spring测试的注释。

向Spring框架的事务基础结构指示要回滚事务的建议方法是从事务上下文中当前正在执行的代码中引发Exception。

并注意:

请注意,默认情况下,Spring Framework的事务基础结构代码仅在运行时未检查的异常的情况下才将事务标记为回滚;也就是说,当抛出的异常是RuntimeException的实例或子类时。


1

对我来说,rollbackFor还不够,所以我不得不把它放进去,并且按预期工作:

@Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)

希望对您有所帮助:-)


1
不,这对TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();您完全没有帮助。在您的帮助下,您完全无法做到
Enerccio '19
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.