【JAVA进阶篇教学】第十九篇:Spring Boot中使用@Transactional注解

时间:2024-05-31 20:22:05

博主打算从0-1讲解下java进阶篇教学,今天教学第十九篇:Spring Boot中使用@Transactional注解。

在Spring Boot应用中,@Transactional注解用于管理事务。它帮助我们确保多个数据库操作在一个事务中执行,这样可以保证数据的一致性和完整性。如果任何一个操作失败,事务将回滚。

目录

一、什么是事务

二、@Transactional注解的使用

三、代码示例

3.1. 创建实体类

3.2. 创建Repository接口

3.3. 创建服务类

3.4. 创建控制器

四、事务失效场景

五、事务传播和隔离级别 

5.1. 事务传播

5.2. 隔离级别


一、什么是事务

事务是一组操作,这些操作要么全部执行成功,要么全部回滚,确保数据的一致性。事务的四个重要特性(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级别。其他都是一样的。

点个关注,不会迷路!