目录
一、什么是事务
事务是一组操作,这些操作要么全部执行成功,要么全部回滚,确保数据的一致性。事务的四个重要特性(ACID)是:
- 原子性 (Atomicity):事务中的所有操作要么全部成功,要么全部失败。
- 一致性 (Consistency):事务开始和结束时,数据处于一致状态。
- 隔离性 (Isolation):并发事务彼此隔离,防止数据不一致。
- 持久性 (Durability):事务提交后,对数据的更改是永久的。
二、@Transactional注解的使用
@Transactional注解可以应用在类或方法上,通常在服务层使用。它的属性包括:
- propagation:事务的传播行为,定义事务的边界。
- isolation:事务的隔离级别,定义事务之间的隔离程度。
- timeout:事务的超时时间。
- readOnly:指示事务是否只读。
- rollbackFor 和 noRollbackFor:指定哪些异常会导致事务回滚。
三、代码示例
让我们来看一个简单的示例,展示如何使用@Transactional注解。
3.1. 创建实体类
@Entity
@Data
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
}
3.2. 创建Repository接口
public interface UserRepository extends JpaRepository<User, Long> {
}
3.3. 创建服务类
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public void createUser(User user) {
userRepository.save(user);
// 其他业务逻辑
}
@Transactional(rollbackFor = Exception.class)
public void createUserWithRollback(User user) throws Exception {
userRepository.save(user);
// 模拟异常
if (user.getName().equals("error")) {
throw new Exception("模拟异常,触发回滚");
}
}
}
3.4. 创建控制器
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public ResponseEntity<String> createUser(@RequestBody User user) {
userService.createUser(user);
return ResponseEntity.ok("用户创建成功");
}
@PostMapping("/withRollback")
public ResponseEntity<String> createUserWithRollback(@RequestBody User user) {
try {
userService.createUserWithRollback(user);
return ResponseEntity.ok("用户创建成功");
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("用户创建失败: " + e.getMessage());
}
}
}
四、事务失效场景
- 方法不是public:@Transactional注解只能应用于public方法。如果应用在非public方法上,事务将不会生效。
- 自调用 (self-invocation):如果一个类内部调用自己的@Transactional方法,事务将不会生效。Spring AOP代理在这种情况下无法拦截调用。
- 事务传播机制不正确:例如,在已经存在的事务中调用需要新事务的方法,而没有正确设置传播属性。
- 异常未被捕获:默认情况下,只有未捕获的运行时异常(继承自RuntimeException)会触发事务回滚。检查受检异常(继承自Exception)不会导致回滚,除非明确指定。
- 异常主动捕获:使用了try...catch,但是却并没有在catch抛出RuntimeException类型异常。
- 没有被spring管理。
- 数据库不支持事务。
五、事务传播和隔离级别
5.1. 事务传播
事务传播定义了事务方法在不同事务上下文中的行为。常见传播类型包括:
- REQUIRED:默认值。如果当前没有事务,创建一个新事务。如果当前已有事务,加入该事务。
- REQUIRES_NEW:总是创建一个新事务。如果当前有事务,挂起该事务。
- NESTED:如果当前有事务,创建一个嵌套事务。如果当前没有事务,创建一个新事务。
5.2. 隔离级别
隔离级别定义了一个事务在何种程度上隔离于其他事务。常见隔离级别包括:
- DEFAULT:使用底层数据库的默认隔离级别。
- READ_UNCOMMITTED:最低隔离级别,可能导致脏读、不可重复读和幻读。
- READ_COMMITTED:防止脏读,但仍可能发生不可重复读和幻读。
- REPEATABLE_READ:防止脏读和不可重复读,但仍可能发生幻读。
- SERIALIZABLE:最高隔离级别,防止脏读、不可重复读和幻读。
注意:Spring和MySql的隔离级别是一样的,但是多了一种DEFAULT级别。其他都是一样的。
点个关注,不会迷路!