1.事务失效
①事务是基于当前线程的,如果事务内有其他线程,那么其他线程的数据库操作不会归本事务管(事务失效,不会回滚内部线程的数据,当前线程的数据是会正常回滚)。
在Java 1.8中list.parallelStream().forEach(item->{ testMapper.insert(...))})操作也会引起事务失效,主要也是因为parallelStream是并行方法,和new一个线程差不多。从而引起上述问题。
②事务失效汇总

spring事务失效的大概原因
1)Bean没有交由Spring容器管理
2)没有配置事务管理器,没有事务注解
3)异常被捕获了
4)抛出的异常与@Transactional设置要捕获的异常不符
5)自身调用,在方法入口处没有事务注解,内部调用的方法才加的事务没有经过Spring代理
6)数据库本身不支持事务
7)事务注解配置以不支持事务的方式运行(@Transactional(propagation = Propagation.NOT_SUPPORTED))
8)方法不是public(官方文档:@Transactional 只能用于 public 的方法上,否则事务不会失效)
9)事务管理器不对。在多数据源情况下,配置多个事务管理器,注意指定正确的事务管理器。

2.被@Transactional和@Async注解标注的方法必须经过spring 来调用(通过spring代理来调用),不能通过this.xxx()来调用(或不能在本类中直接调用)
该方法不会引起事务失效,因为入口方法是通过spring进行调用的,事务方法中的this调用不会引起事务失效。如果入口方法没有经过spring容器,则会失效。

@Override
@Transactional
public void invalidationThis() {
    // mysql 5.7 默认 RR 隔离级别
    Student student = new Student();
    student.setName("散装java");
    studentMapper.insert(student);
    //这么调用不会引起事务失效
    this.saveWithNotTransactional();
}

public void saveWithNotTransactional() {
    Student student = new Student();
    student.setName("谢pro");
    studentMapper.insert(student);
    throw new RuntimeException("手动异常");
}

反例:

@Override
public void invalidationThis() {
    // mysql 5.7 默认 RR 隔离级别
    Student student = new Student();
    student.setName("散装java");
    studentMapper.insert(student);
    //会引起事务失效
    this.saveWithNotTransactional();
}

@Transactional
public void saveWithNotTransactional() {
    Student student = new Student();
    student.setName("谢pro");
    studentMapper.insert(student);
    throw new RuntimeException("手动异常");
}

如果想实现saveWithNotTransactional跑出异常后,不想回滚this.saveWithNotTransactional()之前插入的数据,可以在saveWithNotTransactional方法上加上独立的事务,代码如下:

@Override
@Transactional
public void invalidationThis() {
    // mysql 5.7 默认 RR 隔离级别
    Student student = new Student();
    student.setName("散装java");
    studentMapper.insert(student);
    //通过事务传播行为,@Transactional(propagatioon...)给下面的事务单独去管理
    this.saveWithNotTransactional();
}

@Transactional
public void saveWithNotTransactional() {
    Student student = new Student();
    student.setName("谢pro");
    studentMapper.insert(student);
    throw new RuntimeException("手动异常");
}
最后修改:2022 年 09 月 16 日
如果觉得我的文章对你有用,请随意赞赏