目录
一、什么是事务,为什么要用事务
下面主要介绍声明式事务
二、Spring声明式事务
🍅 1、@Transactional的使用
🎈 事务回滚
声明式事务的使用很简单,只需要在方法上添加@Transactional注解就可以实现了
代码示例:
@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;
}
@Mapper
public interface UserMapper {
@Insert("insert into userinfo(username,password) values (#{username},#{password})")
int add(UserInfo userInfo);
}
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public int add(UserInfo userInfo){
return userMapper.add(userInfo);
}
}
@RequestMapping("/user")
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/add")
@Transactional
public int add(){
// 1.非空判断
UserInfo userInfo = new UserInfo();
userInfo.setUsername("huhu");
userInfo.setPassword("123");
// 2.调用service执行添加
int result = userService.add(userInfo);
System.out.println("result:" + result);
int num = 10/0;
// 3.将结果给前端
return result;
}
}
执行以上代码:结果如下,发生算数异常
但是sql执行没有异常:
🎈注意:异常被捕获,不会发生事务回滚
问题:当自己把程序捕获以后,代表着事务不会发现程序发生了异常,在这种情况下,事务不会发生回滚。
@RequestMapping("/add")
@Transactional
public int add(){
// 1.非空判断
UserInfo userInfo = new UserInfo();
userInfo.setUsername("huhu");
userInfo.setPassword("123");
// 2.调用service执行添加
int result = userService.add(userInfo);
System.out.println("result:" + result);
try{
int num = 10/0;
}catch (Exception e){
}
// 3.将结果给前端
return result;
}
🍅 2、@Transactional 作⽤范围
@Transactional 可以用来修饰类或者方法(public)
- 修饰方法时,只能应用到public方法上面,否则不生效
- 修饰类时,表明该注解对该类的所有public方法都生效
🍅 3、@Transactional 参数说明
一般情况下,以下参数都是默认的
🍅 4、@Transactional的工作原理
@Transactional是基于AOP实现的,AOP又是基于动态代理实现的。
如果目标对象实现了接口,默认情况下就会采用JDK的动态代理,如果目标对象没有实现接口,会使用CGLIB的动态代理。
@Transactional在开始执行业务之前,通过代理先开始事务,在执行成功之后再提交事务。如果中途遇见异常,则回滚事务。
@Transactional实现思路预览:
@Transactional具体执行细节如下图所示:
三、事务的特性以及隔离级别(重要)
🍅 事务的特性(ACID)
🍅 Spring隔离级别
默认情况下,是以SQL的事务隔离级别为主的(Isolation.DEFAULT)。
但是当Sping设置了事务隔离级别以后,就会以Spring的事务隔离级别为主。以下就是以SERIALIZABLE为主的。
@RequestMapping("/add")
@Transactional(isolation = Isolation.SERIALIZABLE)
public int add(){
}
事务的隔离级别保证了多个并发事务执行的可控性。
四、Spring事务的传播机制
🍅为什么需要事务传播机制
🍅 事务传播机制的种类
🎈Propagation.REQUIRED:
默认的事务传播级别,表示如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务
示例:
UserService:
@Transactional
public int add(UserInfo userInfo){
int result = userMapper.add(userInfo);
System.out.println("add result -> "+result);
insert(userInfo);
return result;
}
@Transactional
public int insert(UserInfo userInfo){
int result = userMapper.add(userInfo);
System.out.println("insert resullt -> "+ result);
int num = 10 / 0;
return result;
}
Controller:
@RequestMapping("/add")
@Transactional(propagation = Propagation.REQUIRED)
public int add(){
// 1.非空判断
UserInfo userInfo = new UserInfo();
userInfo.setUsername("万叶");
userInfo.setPassword("123");
// 2.调用service执行添加
int result = userService.add(userInfo);
return result;
}
此时结果是,报错是算数异常,进行了事务回滚,数据库中没有添加任何数据
🎈 Propagation.SUPPORTS
如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行
示例:
UserService
@Transactional(propagation = Propagation.SUPPORTS)
public int add(UserInfo userInfo){
int result = userMapper.add(userInfo);
System.out.println("add result -> "+result);
insert(userInfo);
return result;
}
@Transactional(propagation = Propagation.SUPPORTS)
public int insert(UserInfo userInfo){
int result = userMapper.add(userInfo);
System.out.println("insert resullt -> "+ result);
int num = 10 / 0;
return result;
}
UserController:
@Transactional(propagation = Propagation.SUPPORTS)
public int add(){
// 1.非空判断
UserInfo userInfo = new UserInfo();
userInfo.setUsername("万叶");
userInfo.setPassword("123");
// 2.调用service执行添加
int result = userService.add(userInfo);
return result;
}
当前调用链不存在事务,结果是数据库中添加了两条数据,并且报错是算数异常,但是并没有进行数据回滚
🎈 Propagation.NEVER
以非事务方式运行,如果当前存在事务,则抛出异常
UserController:
@RequestMapping("/add")
//调用链存在事务
@Transactional(propagation = Propagation.REQUIRED)
public int add(){
// 1.非空判断
UserInfo userInfo = new UserInfo();
userInfo.setUsername("万叶");
userInfo.setPassword("123");
// 2.调用service执行添加
int result = userService.add(userInfo);
return result;
}
USerService:
@Transactional(propagation = Propagation.NEVER)
public int add(UserInfo userInfo){
int result = userMapper.add(userInfo);
System.out.println("add result -> "+result);
insert(userInfo);
return result;
}
@Transactional(propagation = Propagation.NEVER)
public int insert(UserInfo userInfo){
int result = userMapper.add(userInfo);
System.out.println("insert resullt -> "+ result);
int num = 10 / 0;
return result;
}
说明程序在发现有事务以后,就没有运行了,不存在事务回滚,而是发现事务以后,程序就没有运行,而是直接抛出异常。
🎈Propagation.NESTED
如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于Propagation.REQUIRED
示例:
UserService:
@Transactional(propagation = Propagation.NESTED)
public int add(UserInfo userInfo){
int result = userMapper.add(userInfo);
System.out.println("add result -> "+result);
return result;
}
@Transactional(propagation = Propagation.NESTED)
public int insert(UserInfo userInfo){
int result = userMapper.add(userInfo);
System.out.println("insert resullt -> "+ result);
try{
int num = 10 / 0;
}catch (Exception e){
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
return result;
}
UserController:
@RequestMapping("/add")
@Transactional(propagation = Propagation.REQUIRED)
public int add(){
// 1.非空判断
UserInfo userInfo = new UserInfo();
userInfo.setUsername("影");
userInfo.setPassword("123");
// 2.调用service执行添加
int result = userService.add(userInfo);
userService.insert(userInfo);
return result;
}
结果如下: