- 七种传播机制
 - 支持当前事务
 - 不支持当前事务
 - 嵌套事务
 
七种传播机制
事务传播机制:解决一个事务在多个方法传递的问题
 传播机制有以下7种
 REQUIRED (默认):如果当前存在事务,则加入该事务,如果不存在事务,则创建一个新事务。
 REQUIRES_NEW:无论当前是否存在事务,都会创建一个新事务。如果当前存在事务,会将其挂起。
 SUPPORTS:如果当前存在事务,则加入该事务,如果不存在事务,则以非事务的方式执行。
 NOT_SUPPORTED:以非事务的方式执行方法,如果当前存在事务,则将其挂起。
 MANDATORY:如果当前存在事务,则加入该事务,如果不存在事务,则抛出异常。
 NEVER:以非事务的方式执行方法,如果当前存在事务,则抛出异常。
 NESTED:如果当前存在事务,则嵌套在该事务中执行;如果不存在事务,则创建一个新事务。嵌套事务是一个独立的子事务,可以单独提交或回滚,但最终必须与外部事务一起提交或回滚。
 
支持当前事务

 那么就涉及到如果方法2/方法3出问题;是全部回滚;还是回滚当前呢?
 以第二个方法Method2为示例;进行演示机制1效果(是否真的Method2出现异常;事务全部都回滚;因为传播机制变成一个事务整体)
 调用链如下;正常逻辑上是调用日志的Interface;但是我们当前需要显示一下错误的信息;所以才选择调用LogService
 
创建日志表、用户表:两张表才能演示才效果是不是都回滚。
CREATE TABLE UserInfo (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(255) NOT NULL,
    password VARCHAR(255) NOT NULL,
    photo VARCHAR(255),
    createtime DATETIME,
    updatetime DATETIME,
    state INT
);
 
CREATE TABLE Log (
    id INT AUTO_INCREMENT PRIMARY KEY,
    timestamp DATETIME NOT NULL,
    message TEXT
);
 
创建实体类对应UserInfo、log
package com.example.demo.entity;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class Log {
    private int id;
    private LocalDateTime timestamp;
    private String message;
}
 
package com.example.demo.entity;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class UserInfo {
    private int id;
    private String username;
    private String password;
    private String photo;
    private LocalDateTime createtime;
    private LocalDateTime updatetime;
    private int state;
}
 
UserService做两件事情;调用UserMapper和调用LogService(正常逻辑调用LogMapper;这里为了异常演示)
package com.example.demo.service;
import com.example.demo.entity.Log;
import com.example.demo.entity.UserInfo;
import com.example.demo.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private LogService logService;
    public int del(Integer id) {
        return userMapper.del(id);
    }
    
    @Transactional(propagation = Propagation.REQUIRED)
    public int add(UserInfo userInfo) {
        // 给用户表添加用户信息
        int addUserResult = userMapper.add(userInfo);
        System.out.println("添加用户结果:" + addUserResult);
        // 添加日志信息
        Log log = new Log();
        log.setMessage("添加用户信息");
        logService.add(log);
        return addUserResult;
    }
}
 
LogService:
package com.example.demo.service;
import com.example.demo.entity.Log;
import com.example.demo.mapper.LogMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
@Service
public class LogService {
    @Autowired
    private LogMapper logMapper;
    @Transactional(propagation = Propagation.REQUIRED)
    public int add(Log log) {
        int result = logMapper.add(log);
        System.out.println("添加日志结果:" + result);
        // 回滚操作
    int num=10/0;
        return result;
    }
    
}
 
这里的演示还不能用回滚操作来代替算数异常;因为内层是要回滚;外层没感知异常。它们都是一个事务;那就出问题了;报错。
UserCOntroller:
package com.example.demo.controller;
import com.example.demo.entity.UserInfo;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
//演示事务传播机制
@RestController
@RequestMapping("/user3")
public class UserController3 {
    @Autowired
    private UserService userService;
    @RequestMapping("/add")
    @Transactional(propagation = Propagation.REQUIRED)
    public int add(String username, String password) {
        if (null == username || null == password ||
                username.equals("") || password.equals("")) return 0;
        UserInfo user = new UserInfo();
        user.setUsername(username);
        user.setPassword(password);
        int result = userService.add(user);
        // 用户添加操作
        return result;
    }
}
 
当形成这样子一个调用链:UserController;UserService;LogService;它们的事务机制都是Propagation.REQUIRED。有事务就加入到事务中。最后执行的结果;添加用户成功了;数据库都回滚成功了。
 
不支持当前事务

 上述代码 @Transactional(propagation = Propagation.REQUIRED)把这里有关的全部都改成requires_new;都会以新的事务去运行。
 预期结果:
 用户添加成功;日志添加失败;各玩各的;日志的回滚了。因为我们在日志里面弄了个算异常。
实际结果:
 整个代码报错了;整个程序都是500;用户的添加那里感知到异常(用户表都添加失败);就会进行回滚。因为没有处理异常;让整个项目都感知到了。
解决方案:单独处理这个异常;或者把我们的代码改成直接回滚操作;而不是算数异常
 
嵌套事务

 独立于外部事务的子事务,它具有自己的保存点,并且可以独立于外部事务进行回滚。如果嵌套事务发生异常并回滚,它将会回滚到自己的保存点,而不影响外部事务。(进行到执行新方法之前的保存点)
 在嵌套事务中,如果方法1调用了方法2,则方法1称为外部事务,方法2称为内部事务。
结果:内部回滚;不影响外部回滚

![[RSIC-V]Milk-V开发板 i2c测试oled及波形输出](https://img-blog.csdnimg.cn/041b873d9a2c415a99d21a57dfdbc327.png)










![[abc周赛复盘] AtCoder Beginner Contest 308 20230701](https://img-blog.csdnimg.cn/c6c1afc761364f739b443d4dca22b0b9.png)






