Why my spring @Transactional with REQUIRED can't rollback?

436 views Asked by At

I try to write a very simple code to test @Transactional, but it won't rollback when I use Propagation.REQUIRED. Here is the code.

    @Component
    public class A {

        private JdbcTemplate jdbcTemplate;

        @Resource(name="dataSource")
        public void setDataSource(DataSource dataSource) {
            this.jdbcTemplate = new JdbcTemplate(dataSource);
        }

        @Transactional(propagation=Propagation.REQUIRED)
        public void add(Person person) throws Exception {
        try {
            String sql = "insert into person (id, name) values(?,?)";
            jdbcTemplate.update(sql, new  Object[{person.getId(),person.getName()});
        } catch (Exception e) {
            throw new RuntimeException();
        }

        @Transactional(propagation=Propagation.REQUIRED)
        public void delete(String id) throws Exception {
            throw new RuntimeException();
            ***throw a RuntimeException on purpose***
        }
    }

    public class cases {

        @Transactional
        public static void testPro() throws Exception {
        try {
            AbstractApplicationContext aac = new ClassPathXmlApplicationContext("beans.xml");
            A a = (A) aac.getBean("a");
            a.add(***a random person***);
            a.delete("99");
        } catch (Exception e) {
            throw new RuntimeException();
        }
    }

    @Test
    public void test() throws Exception {
        testPro();
    }
}

When I test add() method alone by creating a new RuntimeException(), it will rollback. This is what I expected. However, when I run the test() method, the add() method won't rollback when delete() throws a new RuntimeException. It means the add() and delete() are not in a same transaction, but what I want is all the things to be rollback. Please help.

1

There are 1 answers

4
Andreas On BEST ANSWER

@Transactional on testPro() has no effect for 3 separate reasons:

  1. testPro() is static.
  2. Call is internal from test() in same class.
  3. Instance of class cases not created by Spring.

That means that add() and delete() are running in two separate transactions.

To prove it, try changing the propagation on delete() to MANDATORY. It will now throw exception saying that transaction is not in progress (or something to that effect).