spring中12种@Transactional的失效场景(小结)

下面就来详细讲解“Spring中12种@Transactional的失效场景(小结)”。

首先,需要明确的是,@Transactional是用来控制事务的注解,它可以应用于方法、类或接口上,用来确保在执行该方法时开启了一个事务,并在方法结束时提交或回滚事务。但是,在某些情况下,@Transactional注解可能会失效。下面分别讲解12种@Transactional的失效场景:

  1. 在同一个类中调用@Transactional方法

在同一个类中直接调用被@Transactional注解的方法时,事务不会起作用。这是因为@Transactional是通过动态代理去实现的,而如果在同一个类中调用,动态代理并不会被触发。所以,我们需要通过自我注入的方式调用需要使用事务的方法,这样动态代理就会生效。示例代码如下:

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserService userService;

    @Transactional
    public void addUserAndLog() {
        userService.addUser();
        // 记录日志
    }

    @Transactional
    public void addUser() {
        // 添加用户
    }

}
  1. 在非public的方法上使用@Transactional

在许多情况下,我们可能会在一个类中定义私有的或受保护的方法。然而,如果我们在这些方法上使用@Transactional注解,那么事务也会失效。因为,Spring只会拦截public方法,而不会拦截非public方法。示例代码如下:

public class UserServiceImpl implements UserService {

    @Transactional
    public void addUser() {
        // 添加用户
        addUserLog();
    }

    @Transactional
    private void addUserLog() {
        // 添加用户日志
    }

}
  1. 在非事务方法中调用@Transactional方法

如果一个方法没有被@Transactional注解标记,而它又调用了一个被@Transactional注解标记的方法,那么被调用的方法的事务将不会开启。这是因为,被调用的方法已经失去了@Transactional注解的作用。示例代码如下:

@Service
public class UserServiceImpl implements UserService {

    @Transactional
    public void addUser() {
        // 添加用户
        addUserLog();
    }

    @Transactional
    public void addUserLog() {
        // 添加用户日志
    }

    public void addUserAndLog() {
        addUser();
    }

}
  1. 在静态方法上使用@Transactional

由于@Transactional注解是作用在实例方法上的,所以它不能用于静态方法中,否则会失效。示例代码如下:

@Service
public class UserServiceImpl implements UserService {

    @Transactional
    public void addUser() {
        User user = User.builder().username("test").password("123456").build();
        User.save(user);
    }

    @Transactional
    public static void save(User user) {
        // 保存用户
    }

}
  1. @Transactional标注方法的异常被try/catch

如果我们在@Transactional标注的方法中使用try/catch捕获了异常,那么就会导致事务无法回滚。因为一旦我们捕获了异常,它就不会再被传递到Spring事务管理器中,事务管理器就无法识别到异常并进行回滚。示例代码如下:

@Transactional
public void addUser() {
    try {
        // 添加用户
    } catch (Exception e) {
        // 异常捕获
    }
}
  1. @Transactional标注方法的异常类为RuntimeException

如果@Transactional标注的方法中抛出了RuntimeException及其子类的异常,默认情况下事务会回滚,可以通过在异常类上使用@Transaction注解的noRollbackFor属性,来使得事务不回滚。示例代码如下:

@Transactional
public void addUser() {
    throw new RuntimeException("测试异常");
}

@Transactional(noRollbackFor = RuntimeException.class)
public void addUser() {
    throw new RuntimeException("测试异常");
}
  1. @Transactional标注方法和catch块中都抛出异常

如果@Transactional标注的方法中发生了异常,并在catch块中继续抛出了异常,那么事务也会失效。因为catch块中的异常会覆盖原来产生的异常。示例代码如下:

@Transactional
public void addUser() {
    try {
        // 添加用户
    } catch (Exception e) {
        // 处理异常
        throw new RuntimeException("处理异常时出错");
    }
}
  1. @Transactional标注方法所在的类没有被Spring容器管理

@Transactional注解只有在Spring容器管辖的类中才会生效,所以如果@Transactional注解标注在一个未被Spring容器管理的类中,那么它将不起作用。示例代码如下:

public class UserServiceImpl implements UserService {

    @Transactional
    public void addUser() {
        // 添加用户
    }

}
  1. @Transactional标注在类级别上中间加入了非@Transactional的方法,造成事务失效

如果在一个类中,@Transactional注解是针对类级别的,在类中间加了一个没有@Transactional注解的方法,这个非@Transactional方法就会出现事务失效。这是因为,Spring在检测到事务注解时,会动态创建一个代理类进行事务处理,而在代理类中,会通过在方法前后添加事务通知来管理事务。但是,如果我们在被代理的类中间插入了一个方法,Spring就无法保证在代理类中添加事务通知的顺序和正确性了。示例代码如下:

@Service
@Transactional
public class UserServiceImpl implements UserService {

    public void test() {
        // 测试方法
    }

    public void addUser() {
        // 添加用户
    }

}
  1. 使用自调用的方式调用@Transactional方法

如果调用@Transactional方法时使用了自调用的方式,事务也会失效。这是因为自调用会绕过Spring的动态代理。示例代码如下:

@Service
@Transactional
public class UserServiceImpl implements UserService {

    @Autowired
    private UserService userService;

    public void addUserAndLog() {
        addUser();
        this.addUserLog();
    }

    @Transactional
    public void addUser() {
        // 添加用户
    }

    @Transactional
    public void addUserLog() {
        // 添加用户日志
    }

}
  1. 同一个方法内,同时调用多个@Transactional注解的方法,传播属性设置不当

如果在同一个方法内,同时调用多个@Transactional注解的方法,并在这些方法之间使用事务传播属性时,需要特别注意传播属性的设置,否则可能会出现一系列问题,比如事务无法回滚、出现死锁等。示例代码如下:

@Transactional
public void addUser() {
    try {
        // 添加用户
        addUserLog1();
        addUserLog2();
    } catch (Exception e) {
        // 异常处理
    }
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addUserLog1() {
    // 添加用户日志1
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addUserLog2() {
    // 添加用户日志2
}
  1. 在子线程中调用@Transactional标注的方法

在子线程中调用@Transactional标注的方法是不会生效的,因为Spring的事务管理是基于ThreadLocal来实现的,所以在子线程中,Spring的事务管理器无法将事务的上下文传递到新的线程中。所以,如果需要在子线程中使用事务,可以使用TransactionTemplate或者手动同步事务。示例代码如下:

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Transactional
    public void addUser() {
        transactionTemplate.execute(new TransactionCallback<Object>() {
            @Override
            public Object doInTransaction(TransactionStatus transactionStatus) {
                // 在子线程中使用事务
                return null;
            }
        });
    }

}

以上就是“Spring中12种@Transactional的失效场景(小结)”的详细攻略。希望对大家有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:spring中12种@Transactional的失效场景(小结) - Python技术站

(0)
上一篇 2023年5月21日
下一篇 2023年5月21日

相关文章

  • SQL 查找两个表中相同的行

    要查找两个表中相同的行,我们可以使用 SQL 的 JOIN 操作符。JOIN 可以将两个表中的记录组合在一起,基于其中的某些共同的列进行匹配,从而找到相同的行。 以下是两种情况下如何使用 JOIN 查找两个表中相同的行: 情况 1:两个表中有共同的列 假设我们有两个表:Employees 和 Departments。这两个表都有一个共同的列 departme…

    database 2023年3月27日
    00
  • Nginx日志实现访问异常报警详解

    下面我会详细讲解“Nginx日志实现访问异常报警详解”的完整攻略。 1. 概述 Nginx是一个高性能的服务器软件,它支持反向代理、负载均衡、缓存、SSL等功能。同时,Nginx还提供了丰富的日志记录功能,可以记录Web服务器中发生的各种事件。利用Nginx的日志功能,可以实现自动化告警,及时发现并解决访问异常,保障Web服务器的正常运行。 2. Nginx…

    database 2023年5月22日
    00
  • 详解Electron中如何使用SQLite存储笔记

    感谢你对“详解Electron中如何使用SQLite存储笔记”的攻略感兴趣。我将分享以下步骤: 1. 安装SQLite 在Electron中使用SQLite存储笔记,首先需要安装SQLite。可以通过以下命令行进行安装: npm install sqlite3 –save 2. 创建数据库连接 在Electron中打开SQLite数据库,需要引入SQLit…

    database 2023年5月19日
    00
  • 基于@Table注解无法使用及报红的解决

    有些时候,使用JPA的@Table注解进行表映射时,可能会出现无法使用或者报红的情况。针对这种情况,可以采用以下方法进行解决: 1.在pom.xml中引用JPA依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spri…

    database 2023年5月18日
    00
  • DBMS和DSMS的区别

    DBMS和DSMS都是数据管理系统,但它们有一些关键的区别。下面我们将逐个讨论。 DBMS和DSMS的概念 数据库管理系统(DBMS) 数据库管理系统(DBMS)是一种软件系统,用于创建、管理和维护各种类型的数据库。DBMS通常具有多个组件,包括数据库引擎、查询优化器、数据字典、用户界面等。它们支持用于管理数据的各种操作,例如数据定义、数据操作和数据查询等。…

    database 2023年3月27日
    00
  • oracle清空所有表数据

    下面是清空Oracle数据库中所有表数据的完整攻略: 1.备份数据 在进行任何数据库操作之前,请务必备份您的数据。此操作是具有破坏性的,如果您清空了所有表数据,这些数据无法恢复。 2.使用Truncate命令清空数据 Truncate命令可以帮助我们快速地删除表中的所有数据。与delete命令不同,truncate命令以更快的速度执行并释放磁盘空间。 tru…

    database 2023年5月21日
    00
  • Linux系统下安装phpmyadmin方法

    以下是在Linux系统下安装phpMyAdmin的完整攻略。 安装Apache、MySQL及PHP 在安装phpMyAdmin之前,需要先安装Apache、MySQL及PHP。其中,Apache是Web服务器,MySQL是数据库管理系统,而PHP则是用于动态生成Web页面的脚本语言。这里给出安装命令: sudo apt update sudo apt ins…

    database 2023年5月22日
    00
  • MySql 5.7.20安装及data和my.ini文件的配置

    MySQL是一种重要的数据库,下面就MySQL 5.7.20的安装及data和my.ini文件的配置进行详细讲解。 下载安装MySQL 5.7.20 MySQL官网下载链接:https://dev.mysql.com/downloads/mysql/5.7.html#downloads 下载适合自己操作系统版本的MySQL安装包,接着进行安装。 配置data…

    database 2023年5月22日
    00
合作推广
合作推广
分享本页
返回顶部