使用@Transactional注解实现基于注解的事务管理

目录

@Transactional

事务的传播行为

隔离级别、超时时间以及回滚规则

隔离级别

超时时间

回滚规则


@Transactional

基于注解的事务管理是一种常用的方式,可以通过在方法或类上添加注解来声明事务的传播行为、隔离级别、超时时间以及回滚规则等属性。

import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Transactional
    public void updateUser(User user) {
        // 更新用户信息
        userRepository.save(user);
    }

    @Transactional(rollbackFor = Exception.class)
    public void deleteUser(Long userId) {
        // 删除用户
        userRepository.deleteById(userId);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void updateUserAndDeleteUser(User user, Long userId) {
        // 更新用户信息
        userRepository.save(user);
        
        // 删除用户
        userRepository.deleteById(userId);
    }
}

在上面的示例中,@Transactional 注解被添加到了 updateUser()deleteUser()updateUserAndDeleteUser() 方法上。这些方法声明了不同的事务传播行为、回滚规则等属性:

  • updateUser() 方法使用默认的事务传播行为,默认情况下,如果当前没有事务,会开启一个新的事务;如果已经存在事务,则加入到当前事务中。如果方法执行过程中发生异常,事务会回滚。
  • deleteUser() 方法使用了 rollbackFor 属性来指定了回滚的异常类型为 Exception,即当发生任何异常时都会回滚事务。
  • updateUserAndDeleteUser() 方法使用了 propagation 属性来指定了事务的传播行为为 REQUIRED,即如果当前已经存在事务,则加入到当前事务中;如果当前没有事务,则开启一个新的事务。同时,方法中的两个操作都会被包含在同一个事务中,如果方法执行过程中发生异常,事务会回滚。

通过使用 @Transactional 注解,我们可以很方便地在方法级别上声明事务的管理策略,而不需要显式地编写事务管理的代码。

事务的传播行为

事务的传播行为是指在一个事务方法调用另一个事务方法时,事务如何传播的规则。Spring框架提供了几种不同的事务传播行为,可以通过 @Transactional 注解的 propagation 属性来指定。下面是常用的事务传播行为:

  1. REQUIRED(默认):如果当前没有事务,则开启一个新的事务;如果当前已经存在事务,则加入到当前事务中。

  2. SUPPORTS:如果当前存在事务,则加入到当前事务中;如果当前没有事务,则以非事务的方式执行。

  3. MANDATORY:必须在事务中执行,如果当前没有事务,则抛出异常。

  4. REQUIRES_NEW:无论当前是否存在事务,都会开启一个新的事务,如果当前存在事务,则将当前事务挂起。

  5. NOT_SUPPORTED:以非事务的方式执行,如果当前存在事务,则将当前事务挂起。

  6. NEVER:以非事务的方式执行,如果当前存在事务,则抛出异常。

  7. NESTED:如果当前存在事务,则在当前事务的嵌套事务中执行,如果当前没有事务,则开启一个新的事务。如果外部事务提交,那么嵌套事务也会被提交;如果外部事务回滚,那么嵌套事务也会被回滚。

通过合适地选择事务的传播行为,可以实现不同粒度的事务控制,并确保事务的一致性和可靠性。

隔离级别、超时时间以及回滚规则

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 30, rollbackFor = Exception.class)
    public void updateUser(User user) {
        userRepository.update(user);
    }

    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 30, rollbackFor = Exception.class)
    public void deleteUser(int userId) {
        userRepository.delete(userId);
    }

    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 30, rollbackFor = Exception.class)
    public void createUser(User user) {
        userRepository.create(user);
    }

    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 30, rollbackFor = Exception.class)
    public User getUser(int userId) {
        return userRepository.getById(userId);
    }
}

在上面的示例中,@Transactional 注解被应用于 updateUserdeleteUsercreateUsergetUser 方法上,并指定了事务的传播行为为 REQUIRED,隔离级别为默认级别,超时时间为 30 秒,回滚规则为遇到任何异常都回滚。

隔离级别

事务的隔离级别定义了一个事务对数据库中数据的可见性程度,以及事务之间的相互影响程度。在数据库中,通常有以下四种隔离级别:

  1. 读未提交(Read Uncommitted):一个事务可以读取到另一个事务未提交的数据。这种隔离级别下可能会发生脏读、不可重复读和幻读的问题。

  2. 读已提交(Read Committed):一个事务只能读取到已经提交的数据。这种隔离级别下可以避免脏读,但仍可能发生不可重复读和幻读的问题。

  3. 可重复读(Repeatable Read):一个事务在其执行期间可以多次读取相同的数据,并且其他事务在该事务执行期间不能对这些数据进行修改。这种隔离级别下可以避免脏读和不可重复读,但仍可能发生幻读的问题。

  4. 串行化(Serializable):最高的隔离级别,确保每个事务都完全独立运行,事务之间不会相互干扰。串行化隔离级别可以避免所有类型的并发问题,但性能较低,因为它会对数据库中的数据进行锁定。

在Spring框架中,使用 @Transactional 注解来管理事务,可以通过 isolation 属性来指定事务的隔离级别。例如:

@Transactional(isolation = Isolation.READ_COMMITTED)
public void updateUser(User user) {
    userRepository.update(user);
}

在这个示例中,事务的隔离级别被设置为 READ_COMMITTED,表示事务只能读取到已经提交的数据。

超时时间

例:timeout = 30

回滚规则

事务回滚规则定义了在何种情况下事务应该回滚(撤销)已经执行的操作。通常,当事务执行过程中出现异常或者特定条件不满足时,系统会根据事务回滚规则来决定是否回滚事务。常见的回滚规则包括:

  1. 默认回滚:当事务执行过程中出现未捕获的异常时,默认情况下事务会自动回滚。这是最常见的回滚规则,可以保证在异常情况下数据的一致性和完整性。

  2. 自定义回滚条件:有时候需要根据特定的条件来决定是否回滚事务。这种情况下,可以在代码中编写逻辑来判断是否满足回滚条件,然后通过编程的方式调用事务管理器来手动回滚事务。

在Spring框架中,可以通过 @Transactional 注解的 rollbackFornoRollbackFor 属性来定义回滚规则。例如:

@Transactional(rollbackFor = Exception.class)
public void updateUser(User user) {
    // 更新用户信息的代码
}

在这个示例中,rollbackFor 属性指定了当出现 Exception 类型的异常时需要回滚事务。如果不指定 rollbackFor 属性,则默认情况下只有运行时异常会触发事务回滚。

除了使用 rollbackFor 属性外,还可以使用 noRollbackFor 属性来指定哪些异常不应该触发事务回滚。例如:

@Transactional(noRollbackFor = {CustomException.class})
public void updateUser(User user) throws CustomException {
    // 更新用户信息的代码
}

在这个示例中,noRollbackFor 属性指定了当出现 CustomException 类型的异常时不需要回滚事务。

// 定义自定义异常类
class CustomException extends Exception {

    // 定义一个错误码属性
    private int errorCode;

    // 构造方法,接收错误消息和错误码
    public CustomException(String message, int errorCode) {
        super(message); // 调用父类的构造方法
        this.errorCode = errorCode;
    }

    // 获取错误码的方法
    public int getErrorCode() {
        return errorCode;
    }
}

// 测试类
public class Main {
    // 模拟一个方法,可能会抛出自定义异常
    public static void divide(int dividend, int divisor) throws CustomException {
        if (divisor == 0) {
            // 如果除数为0,抛出自定义异常
            throw new CustomException("除数不能为0", 1001);
        } else {
            // 计算除法
            int result = dividend / divisor;
            System.out.println("结果:" + result);
        }
    }

    // 主方法
    public static void main(String[] args) {
        try {
            // 调用 divide 方法,可能抛出自定义异常
            divide(10, 0);
        } catch (CustomException e) {
            // 捕获自定义异常
            System.out.println("发生自定义异常,错误消息:" + e.getMessage());
            System.out.println("错误码:" + e.getErrorCode());
        }
    }
}

在这个示例中,定义了一个 CustomException 自定义异常类,模拟了一个 divide 方法可能抛出异常的情况。在 main 方法中调用 divide 方法时,通过 try-catch 块捕获可能抛出的自定义异常,并进行相应的处理。

相关推荐

  1. 使用@Transactional注解实现基于注解事务管理

    2024-02-19 04:10:02       28 阅读
  2. 【Spring】5.Spring事务@Transactional注解剖析

    2024-02-19 04:10:02       12 阅读
  3. 利用事务实现转账(基于注解配置)

    2024-02-19 04:10:02       44 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-02-19 04:10:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-19 04:10:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-19 04:10:02       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-19 04:10:02       20 阅读

热门阅读

  1. 力扣代码学习日记四

    2024-02-19 04:10:02       35 阅读
  2. 最长公共子序列和最长公共子串

    2024-02-19 04:10:02       40 阅读
  3. Unity笔记:数据持久化的几种方式

    2024-02-19 04:10:02       39 阅读