本文讲解 Spring Boot 如何使用声明式事务管理。
Spring 支持声明式事务,使用 @Transactional 注解在方法上表明这个方法需要事务支持。此时,Spring 拦截器会在这个方法调用时,开启一个新的事务,当方法运行结束且无异常的情况下,提交这个事务。
Spring 提供一个 @EnableTransactionManagement 注解在配置类上来开启声明式事务的支持。使用了 @EnableTransactionManagement 后,Spring 会自动扫描注解 @Transactional 的方法和类。
Spring Boot 默认集成事务,所以无须手动开启使用 @EnableTransactionManagement 注解,就可以用 @Transactional注解进行事务管理。我们如果使用到 spring-boot-starter-jdbc 或 spring-boot-starter-data-jpa,Spring Boot 会自动默认分别注入
DataSourceTransactionManager 或 JpaTransactionManager。
我们在前文《 Spring Boot 揭秘与实战(二) 数据存储篇 - MySQL 》的案例上,进行实战演练。
我们先创建一个实体对象。为了便于测试,我们对外提供一个构造方法。
public class Author { private Long id; private String realName; private String nickName; public Author() {} public Author(String realName, String nickName) { this.realName = realName; this.nickName = nickName; } // SET和GET方法 }
这里,为了测试事务,我们只提供一个方法新增方法。
@Repository("transactional.authorDao") public class AuthorDao { @Autowired private JdbcTemplate jdbcTemplate; public int add(Author author) { return jdbcTemplate.update("insert into t_author(real_name, nick_name) values(?, ?)", author.getRealName(), author.getNickName()); } }
我们提供三个方法。通过定义Author的realName字段长度必须小于等于5,如果字段长度超过规定长度就会触发参数异常。
值得注意的是,noRollbackFor修饰表明不做事务回滚,rollbackFor修饰的表明需要事务回滚。
@Service("transactional.authorService") public class AuthorService { @Autowired private AuthorDao authorDao; public int add1(Author author) { int n = this.authorDao.add(author); if(author.getRealName().length() > 5){ throw new IllegalArgumentException("author real name is too long."); } return n; } @Transactional(noRollbackFor={IllegalArgumentException.class}) public int add2(Author author) { int n = this.authorDao.add(author); if(author.getRealName().length() > 5){ throw new IllegalArgumentException("author real name is too long."); } return n; } @Transactional(rollbackFor={IllegalArgumentException.class}) public int add3(Author author) { int n = this.authorDao.add(author); if(author.getRealName().length() > 5){ throw new IllegalArgumentException("author real name is too long."); } return n; } }
@RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(WebMain.class) public class TransactionalTest { @Autowired protected AuthorService authorService; //@Test public void add1() throws Exception { authorService.add1(new Author("梁桂钊", "梁桂钊")); authorService.add1(new Author("LiangGzone", "LiangGzone")); } //@Test public void add2() throws Exception { authorService.add2(new Author("梁桂钊", "梁桂钊")); authorService.add2(new Author("LiangGzone", "LiangGzone")); } @Test public void add3() throws Exception { authorService.add3(new Author("梁桂钊", "梁桂钊")); authorService.add3(new Author("LiangGzone", "LiangGzone")); } }
我们分别对上面的三个方法进行测试,只有最后一个方法进行了事务回滚。