跳至主要內容

1、Spring 的 7 种事务传播行为

安图新大约 3 分钟

1、Spring 的 7 种事务传播行为

1.7 种事务传播行为

Spring 中定义了七种事务传播行为,分别是:(propagation:n.传播,宣传,培养)

1、 REQUIRED:如果当前存在事务,则加入该事务,否则新建一个事务这是最常见的传播行为,也是默认的传播行为;
2、 SUPPORTS:支持当前事务,如果当前不存在事务,则以非事务方式执行;
3、 MANDATORY:强制要求当前存在事务,如果不存在事务,则抛出异常*(mandatory:adj.强制的)*;
4、 REQUIRES_NEW:重新开启一个新的事务,如果当前存在事务,则挂起该事务(注意:默认的事务隔离级别——可重复读中,开启的新事务读不到之前挂起事务的操作,而且如果操作相同的表会导致锁表,一定要谨慎使用!);
5、 NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,则挂起该事务;
6、 NEVER:以非事务方式执行操作,如果当前存在事务,则抛出异常;
7、 NESTED:如果当前存在事务,则嵌套事务中执行嵌套事务是相对于外部事务而言的,它可以独立提交或回滚,但是嵌套事务的提交或回滚并不会对外部事务产生影响如果外部事务不存在,那么NESTEDREQUIRED的效果是一样的该传播行为只有在使用 JDBC 事务时才有效;

事务传播行为决定了一个方法执行时如何参与到已有的事务中,或者如何创建新的事务。需要根据实际的业务场景和要求来选择合适的事务传播行为。

2.事务使用示例

使用事务传播行为需要在方法上加上 @Transactional 注解,并指定传播行为,例如:

@Transactional(propagation=Propagation.REQUIRED)
public void doSomething() {


    // ...
}

这样就将 doSomething() 方法设置为在当前存在事务时,加入该事务,如果不存在事务,则创建一个新的事务。如果需要设置其他的传播行为,只需要将 Propagation.REQUIRED 替换成其他传播行为即可。同时,需要保证 @Transactional 注解在方法所在的类上被正确地启用了事务管理。

3.REQUIRES_NEW 事务传播行为使用示例

REQUIRES_NEW 是 Spring 中的一个事务传播行为。

  • 作用: 创建一个新的事务,并暂停当前事务(如果存在)。
  • 使用场景: 可以使用这个传播行为来确保一个方法执行时独立于调用它的方法所在的事务。
  • 场景示例: 日志记录场景。PostgreSQL 同一事务中,如果事务中间有报错,后面的所有 SQL 都会执行失败。这时我们就非常需要 PRAOPAGATION_REQUIRES_NEW 这种事务传播行为。

3.1 事务传播图

下面是一个使用 REQUIRES_NEW 事务传播行为的示例:

 
 

3.2 TUserAServiceImpl.java

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.demo.module.entity.TUser;
import com.demo.module.mapper.TUserMapper;
import com.demo.module.service.TUserAService;
import com.demo.module.service.TUserBService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author ACGkaka
 * @since 2021-04-25
 */
@Slf4j
@Service
public class TUserAServiceImpl extends ServiceImpl<TUserMapper, TUser> implements TUserAService {



    @Autowired
    private TUserBService tUserBService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addUserA() {


        // 添加用户A
        TUser user = new TUser(null, "username_aaa", "pwd_aaa", LocalDateTime.now(), LocalDateTime.now());
        this.save(user);
        // 调用方法B
        try {


            tUserBService.addUserB();
        } catch (Exception e) {


            log.error("addUserA filed. reason: {}", e.getMessage());
        }
    }
}

3.3 TUserBServiceImpl.java

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.demo.module.entity.TUser;
import com.demo.module.mapper.TUserMapper;
import com.demo.module.service.TUserBService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author ACGkaka
 * @since 2021-04-25
 */
@Slf4j
@Service
public class TUserBServiceImpl extends ServiceImpl<TUserMapper, TUser> implements TUserBService {



    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void addUserB() {


        // 添加用户B
        TUser user = new TUser(null, "username_bbb", "pwd_bbb", LocalDateTime.now(), LocalDateTime.now());
        this.save(user);
        throw new RuntimeException("抛出异常");
    }
}

整理完毕,完结撒花~