@Transactional注解超详细

本文已收录于专栏
《Java》

本文前言

  @Transactional注解是Spring框架中用于声明式事务管理的关键注解。本文将深入探讨@Transactional注解的作用、使用方式和常见属性,并结合代码实例演示其在实际项目中的应用,以帮助读者更好地理解和使用该注解。

概念说明

  @Transactional注解是Spring框架提供的一个用于声明式事务管理的注解。它可以应用在方法或类上,用于标识需要进行事务管理的方法或类。通过使用@Transactional注解,我们可以更加方便地管理事务,保障数据的一致性和可靠性。在介绍@Transactional注解之前,我们先来了解一下事务的基本概念。事务具有四个基本特性:「原子性 」「一致性 」「隔离性 」「持久性 」

  • 「原子性 」表示一个事务中的所有操作要么全部成功执行,要么全部失败回滚;
  • 「一致性 」表示事务执行前后数据库的状态保持一致;
  • 「隔离性 」表示多个事务并发执行时,彼此之间是相互隔离的,互不干扰;
  • 「持久性 」表示一旦事务提交,其所做的修改将永久保存在数据库中。

使用说明

  使用@Transactional注解的方式 @Transactional注解可以应用在方法或类上。

  1. 当应用在方法上时,该方法将被纳入事务管理;
    在这里插入图片描述
    在这里插入图片描述
  2. 当应用在类上时,该类中的所有方法都将被纳入事务管理。
    在这里插入图片描述
    在这里插入图片描述
    3.常用属性 @Transactional注解有许多属性可供配置,其中一些常用的属性包括事务传播行为、隔离级别和超时设置。事务传播行为用于定义事务方法与其他事务方法的关系;隔离级别用于定义事务方法之间的隔离程度;超时设置用于定义事务方法的最大执行时间。我们可以根据应用程序的需求来灵活配置这些属性。
    在这里插入图片描述

底层实现

public class TransactionalAnnotationProcessor {
    private PlatformTransactionManager transactionManager;

    public TransactionalAnnotationProcessor(PlatformTransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }

    public Object process(Object target, Method method, Object[] args) throws Throwable {
        Transactional transactional = method.getAnnotation(Transactional.class);
        TransactionStatus transactionStatus = null;

        try {
            // 开启事务
            transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());

            // 执行目标方法
            Object result = method.invoke(target, args);

            // 提交事务
            transactionManager.commit(transactionStatus);

            return result;
        } catch (Exception ex) {
            // 回滚事务
            if (transactionStatus != null) {
                transactionManager.rollback(transactionStatus);
            }

            throw ex;
        }
    }
}

  TransactionalAnnotationProcessor类是一个简化版本的注解解析器。它接收一个PlatformTransactionManager对象作为构造函数的参数,用于管理事务。process()方法接收目标对象、目标方法和方法参数作为参数。该方法首先通过反射获取目标方法上的@Transactional注解,然后根据注解的配置开启事务。接着,执行目标方法,并根据方法执行的结果决定是提交事务还是回滚事务。

注意事项

  1. Transactional注解标注方法修饰符为非public
   @Transactional(rollbackFor = Exception.class)
    private void executeInsertSQL(String tableName,String columnName,String placeholderOfColumnName,List<String> fieldNameList,List<Object> valuesOfField ) throws SQLException {
        TransactionStatus transactionStatus=null;
        PlatformTransactionManager transactionManager=null;
        try{
            String sql = "insert into "+tableName+"  (" + columnName + ") values(" + placeholderOfColumnName + ")";
            //获取EntityManager对象
            EntityManager entityManager = Actor.applicationContext.getBean(EntityManager.class);
            transactionManager = Actor.applicationContext.getBean(PlatformTransactionManager.class);

            //手动开启事务
            transactionStatus= transactionManager.getTransaction(new DefaultTransactionDefinition());
            // 使用EntityManager执行JPA操作
            Query nativeQuery = entityManager.createNativeQuery(sql);
            for (int i=0;i<valuesOfField.size();i++){
                nativeQuery.setParameter(fieldNameList.get(i), valuesOfField.get(i));
            }

            nativeQuery.executeUpdate();
            //手动提交事务
            transactionManager.commit(transactionStatus);
        }catch (Exception e){
            if(transactionStatus!=null ){
                //回滚事务
                transactionManager.rollback(transactionStatus);
            }
            e.printStackTrace();

        }
    }

在这里插入图片描述

  Transactional注解标注方法修饰符为非public时,@Transactional注解将会不起作用。因此在方法抛出异常时,nativeQuery.executeUpdate();操作不会进行回滚。如果executeInsertSQL方法改为public的话将会正常开启事务,然后在决定是提交事务还是回滚。

  1. 在类内部非@Transactional标注的方法,调用类内部@Transactional标注的方法
   public void text() throws SQLException {
        List<Object> objects = new ArrayList<>();
        List<String> stringList = new ArrayList<>();
        this.executeInsertSQL("12","21","wzl",stringList,objects);
    }

    /*
     * @description:执行插入的sql语句
     * @author: wuzilong
     * @date: 2023/6/12 17:10
     * @param: [tableName, fieldStr, valueStr, fieldNameList, values]
     * @return: void
     **/
    @Transactional(rollbackFor = Exception.class)
    public void executeInsertSQL(String tableName,String columnName,String placeholderOfColumnName,List<String> fieldNameList,List<Object> valuesOfField ) throws SQLException {
        TransactionStatus transactionStatus=null;
        PlatformTransactionManager transactionManager=null;
        try{
            String sql = "insert into "+tableName+"  (" + columnName + ") values(" + placeholderOfColumnName + ")";
            //获取EntityManager对象
            EntityManager entityManager = Actor.applicationContext.getBean(EntityManager.class);
            transactionManager = Actor.applicationContext.getBean(PlatformTransactionManager.class);

            //手动开启事务
            transactionStatus= transactionManager.getTransaction(new DefaultTransactionDefinition());
            // 使用EntityManager执行JPA操作
            Query nativeQuery = entityManager.createNativeQuery(sql);
            for (int i=0;i<valuesOfField.size();i++){
                nativeQuery.setParameter(fieldNameList.get(i), valuesOfField.get(i));
            }

            nativeQuery.executeUpdate();
            //手动提交事务
            transactionManager.commit(transactionStatus);
        }catch (Exception e){
            if(transactionStatus!=null ){
                //回滚事务
                transactionManager.rollback(transactionStatus);
            }
            e.printStackTrace();

        }
    }

在这里插入图片描述
  调用一个方法在类内部调用内部被@Transactional标注的事务方法,运行结果是事务不会正常开启,nativeQuery.executeUpdate();操作将会保存到数据库不会进行回滚。

  1. 事务方法内部捕捉了异常,没有抛出新的异常
    @Transactional(rollbackFor = Exception.class)
    public void executeInsertSQL(String tableName,String columnName,String placeholderOfColumnName,List<String> fieldNameList,List<Object> valuesOfField ) throws SQLException {
        TransactionStatus transactionStatus=null;
        PlatformTransactionManager transactionManager=null;
        try{
            String sql = "insert into "+tableName+"  (" + columnName + ") values(" + placeholderOfColumnName + ")";
            //获取EntityManager对象
            EntityManager entityManager = Actor.applicationContext.getBean(EntityManager.class);
            transactionManager = Actor.applicationContext.getBean(PlatformTransactionManager.class);

            //手动开启事务
            transactionStatus= transactionManager.getTransaction(new DefaultTransactionDefinition());
            // 使用EntityManager执行JPA操作
            Query nativeQuery = entityManager.createNativeQuery(sql);
            for (int i=0;i<valuesOfField.size();i++){
                nativeQuery.setParameter(fieldNameList.get(i), valuesOfField.get(i));
            }

            nativeQuery.executeUpdate();
            //手动提交事务
            transactionManager.commit(transactionStatus);
        }catch (Exception e){
            System.out.println("抛出了一个异常");

        }
    }

在这里插入图片描述
  运行程序发现,虽然抛出异常,但是异常被捕捉了,没有抛出到方法外, nativeQuery.executeUpdate();操作并没有回滚。

  1. 在使用@Transactional注解的时候rollback属性默认抛出了未检查 unchecked 异常(继
    承⾃ RuntimeException 的异常)或者 Error 才回滚事务,其他异常不会触发回滚事务。rollbackFor 可以指定能够触发事务回滚的异常类型。
    在这里插入图片描述
//⾃定义的异常可以进⾏回滚
@Transactional( propagation = Propagation .REQUIRED , rollbackFor = MyException . class
//所有的异常可以进⾏回滚
@Transactional(rollbackFor = Exception.class)

注解扩展

在这里插入图片描述
  以上是一些常用的与@Transactional注解相似的注解,它们都可以用来简化开发、提高代码的可读性和可维护性。您可以根据实际需求选择合适的注解来使用。

总结提升

  @Transactional注解是Spring框架中用于声明式事务管理的关键注解。通过使用@Transactional注解,我们可以更加方便地管理事务,保障数据的一致性和可靠性。在实际项目中,合理使用@Transactional注解可以提高「开发效率 」和代码「可维护性 」。希望本文能帮助读者更好地理解和使用@Transactional注解。


🎯 此文章对你有用的话记得留言+点赞+收藏哦🎯
  • 32
    点赞
  • 96
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
@Transactional注解Spring框架中用于管理事务的注解,它可以应用于类或方法上。使用该注解可以确保一个方法或类中的操作要么全部成功提交,要么全部回滚,从而保证数据的完整性和一致性。下面是@Transactional注解详细使用方法: 1.在类上使用@Transactional注解 在类上使用@Transactional注解,表示该类中的所有方法都将被纳入到事务管理中。例如: ```java @Service @Transactional public class UserServiceImpl implements UserService { // ... } ``` 2.在方法上使用@Transactional注解 在方法上使用@Transactional注解,表示该方法将被纳入到事务管理中。例如: ```java @Service public class UserServiceImpl implements UserService { @Override @Transactional public void addUser(User user) { // ... } } ``` 3.设置@Transactional注解的属性 @Transactional注解还有一些属性可以设置,例如: - propagation:事务的传播行为,默认值为REQUIRED。 - isolation:事务的隔离级别,默认值为DEFAULT。 - readOnly:是否只读事务,默认值为false。 - timeout:事务时时间,默认值为-1,表示使用数据库默认时时间。 - rollbackFor:指定哪些异常需要回滚事务。 - noRollbackFor:指定哪些异常不需要回滚事务。 例如: ```java @Service public class UserServiceImpl implements UserService { @Override @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false, timeout = 30, rollbackFor = Exception.class) public void addUser(User user) { // ... } } ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

武梓龙_Wzill

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值