本文纯个人读书笔记,书籍《一步一步学 Spring Boot 2》
如果喜欢,可直接购买书籍。如有侵权,请联系删除
一、Spring 事务
Spring 事务主要是用来保证数据的完整性和一致性。Spring 在不同的事务管理 API 之上定义了一个抽象层,而应用程序开发人员不必了解底层的事务管理 API,就可以使用 Spring 的事务管理机制。
Spring 既支持编程式事务管理(也称编码式事务),也支持声明式的事务管理。
编程式事务管理是指将事务管理代码嵌入到业务方法中来控制事务的提交和回滚。在编程式事务中,必须在每个业务操作中包含额外的事务管理代码。
声明式事务管理是指将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。大多数情况下声明式事务管理比编程式事务管理更好用。Spring 通过 Spring AOP 框架支持声明式事务管理。
Spring 在不同的事务管理 API 之上定义了一个抽象层 PlatformTransactionManager,并且提供了许多事务管理器的实现:DataSourceTransactionManager、JdoTransactionManager、JpaTransactionManager、以及HibernateTransactionManager等等。开发人员不必了解底层的事务管理 API,就可以使用 Spring 的事务管理机制。
1.声明式事务
Spring 声明式事务目前比较流行的是使用注解方式。我们可以使用 @Transactional 注解在类或者方法上表明该类或者方法需要事务支持。被注解的类或者方法被调用时,Spring开启一个新的事务,当方法正常运行时,Spring 会提交这个事务。
这里需要注意的是,@Transactional 注解来自 org.springframework.transaction.annotation。Spring 提供了@EnableTransactionManagement 注解在配置类上来开启声明式事务的支持。使用 @EnableTransactionManagement 后,Spring 容器会自动扫描注解 @Transactional 的方法和类。
2.Spring 传播行为
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。事务的传播行为可以在 @Transactional 的属性中指定。Spring定义了7种传播行为,
Spring 传播行为:
@Transactional 可以通过 propagation 属性定义事务的传播行为,属性值分别为:REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER 和 NESTED,对应上面的 7 个值。
3.Spring 隔离级别
多个事务并发运行时,经常会操作相同的数据来完成各自的任务,这时候会导致一些问题,
① 脏读(Dirty reads): 脏读发生在一个事务读取了另一个事务改写但尚未提交的数据。如果改写在稍后被回滚了,那么第一个事务获取的数据就是无效的。
② 不可重复读(Nonrepeatable read): 不可重复读发生在一个事务执行相同的查询两次或两次以上,但是每次都得到不同的数据时。这通常是因为另一个并发事务在两次查询期间更新了数据。
③ 幻读(Phantom read): 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录。
针对这些问题,Spring 提供了五种事务的隔离级别。
Spring 隔离级别:
@Transactional 可以通过 isolation 属性定义隔离级别,属性值分别为:DEFAULT、READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ 和 SERIALIZABLE,分别对应上面的 5 个值。
二、Spring Boot 中事务的使用
Spring Boot 默认对 JPA、JDBC、Mybatis 开启了事事务,直接使用注解 @Transactional 就可以。如果使用其它的 ORM 框架,就需要自己配置相关的事物管理器。
其他与正常的事务使用没有任何区别,分为类级别事务和方法级别事务。
类级别事务:
@Service
@Transactional
public class UserServiceImpl implements UserService {
......
}
方法级别事务:
@Override
@Transactional
public User save(User user) {
// 出现空指针异常
userRepository.save(user);
return user;
}
注解在类上的时候,此类的所有 public 方法都开启事务的。如果类级别和方法级别同时使用了 @Transactional 注解,则方法级别注解覆盖类级别注解。
三、测试
修改 com.xiaoyue.demo.service.impl.UserServiceImpl 的 save 方法,模拟出现异常。
UserServiceImpl.java:
@Service
@Transactional
public class UserServiceImpl implements UserService {
@Resource
private UserRepository userRepository;
@Override
public User save(User user) {
userRepository.save(user);
// 模拟异常
int i = 10 / 0;
return user;
}
......
}
在测试类 DemoApplicationTests.java 中添加测试代码并运行。
DemoApplicationTests.java:
@Test
public void testTransaction () {
User user =new User( );
user.setId ("5");
user.setName("test");
user.setPassword ("123456") ;
userService.save(user);
}
运行结果会发现数据库没有数据添加。如果在 service 中把 @Transactional 去掉,可以发现,添加成功。说明事务生效。