Spring事务和事务传播机制

目录

一:Spring中事务的实现

二:Spring事务的操作

2.1:Spring编程式实现事务

2.1.1:User表

2.1.2:Mapper接口声明的方法

2.1.3:Service层

2.1.4:Controller层

2.2:Spring声明式事务(自动)

2.2.1:实现案例

[2.2.2: @Transactional注意事项](#2.2.2: @Transactional注意事项)

三:事务的隔离级别

3.1:原子性

3.2:一致性

3.3:持久性

3.4:隔离性

3.4.1:脏读

3.4.2:不可重复读

3.4.3:幻读

3.4.4:Spring事务隔离级别

四:Spring事务传播机制

4.1:什么是事务传播机制?

4.2:事务传播机制有哪些?

​编辑


一:Spring中事务的实现

Spring中的事务操作分为两类:

1:编程式事务(手动写代码操作事务)

2:声明式事务(利用注解自动开启和提交事务)

二:Spring事务的操作

在spring操作中,也分为三个步骤 ,开启事务,回滚事务,提交事务。

下面,我们通过案例来进行操作。

2.1:Spring编程式实现事务

2.1.1:User表

sql 复制代码
#创建用户表
create table user(
    userId int primary key auto_increment,
    #约定用户名是独一无二的
    username varchar(64) unique ,
    #密码
    password varchar(64)
);

2.1.2:Mapper接口声明的方法

在mapper中声明的方法,我们用的是添加一个用户信息的操作。返回的数字代表影响的行数。

java 复制代码
@Mapper
public interface UserMapper {
    //返回int的数据
    int addUserInfo(UserInfo userInfo);
}

2.1.3:Service层

java 复制代码
@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
    public Integer addUserInfo(UserInfo userInfo){
        return userMapper.addUserInfo(userInfo);
    }
}

2.1.4:Controller层

java 复制代码
@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
    //添加这个注解,将事务管理器引入进来
    @Autowired
    private DataSourceTransactionManager transactionManager;
    //设置事务的属性
    @Autowired
    private TransactionDefinition transactionDefinition;
    //返回受影响的行数
    @RequestMapping("/add")
    public Integer add(UserInfo userInfo){
        //第一步:非空校验
        if(userInfo==null||!StringUtils.hasLength(userInfo.getUsername())
        ||!StringUtils.hasLength(userInfo.getPassword())){
            return 0;
        }
        //1.开启事务,得到并开启事务
        TransactionStatus transaction = transactionManager.getTransaction(transactionDefinition);
        Integer integer = userService.addUserInfo(userInfo);
        System.out.println(integer);
        //2:回滚事务
        transactionManager.rollback(transaction);
        return integer;

    }

}

此时,由于我们对添加用户信息这一条进行了回滚,所以,新的用户信息添加不到数据库当中,但是返回的数值仍旧是1.


但当我们将回滚事务转变成提交事务,我们看数据库里面能不能得到添加的用户信息。

java 复制代码
@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
    //添加这个注解,将事务管理器引入进来
    @Autowired
    private DataSourceTransactionManager transactionManager;
    //设置事务的属性
    @Autowired
    private TransactionDefinition transactionDefinition;
    //返回受影响的行数
    @RequestMapping("/add")
    public Integer add(UserInfo userInfo){
        //第一步:非空校验
        if(userInfo==null||!StringUtils.hasLength(userInfo.getUsername())
        ||!StringUtils.hasLength(userInfo.getPassword())){
            return 0;
        }
        //1.开启事务,得到并开启事务
        TransactionStatus transaction = transactionManager.getTransaction(transactionDefinition);
        Integer integer = userService.addUserInfo(userInfo);
        System.out.println(integer);
        //2:回滚事务
        transactionManager.commit(transaction);
        return integer;

    }

}

运行结果:

2.2:Spring声明式事务(自动)

在controller层添加@Transactional这个注解,就可以开启事务了。

特点:

1:@Transaction这个注解可以加在类和方法上,加在类上代表这个类里面的public方法,都具有事务,加在方法上,代表此处的方法具有事务。

2:@Transactional,在方法执行前开启事务,在方法执行后提交事务,如若在方法执行过程中,出现异常,则回滚事务。

2.2.1:实现案例

java 复制代码
  @Transactional
    @RequestMapping("/insert")
    public Integer insert(UserInfo userInfo){
        if(userInfo==null||!StringUtils.hasLength(userInfo.getUsername())
        ||!StringUtils.hasLength(userInfo.getPassword())){
            return 0;
        }
        Integer integer = userService.addUserInfo(userInfo);
        return integer;
    }

上述代码中,在方法运行过程中,并没有出现异常,那么,就会自动提交事务。倘若,我们给这个方法中添加算数异常,看看会发生什么?

java 复制代码
 @Transactional
    @RequestMapping("/insert")
    public Integer insert(UserInfo userInfo){
        if(userInfo==null||!StringUtils.hasLength(userInfo.getUsername())
        ||!StringUtils.hasLength(userInfo.getPassword())){
            return 0;
        }
        Integer integer = userService.addUserInfo(userInfo);
        System.out.println(integer);
        //搞一个算数异常
        int num=10/0;
        return integer;
    }

此时就会报出算数异常,在方法中出现算数异常,那么,此时,就会出现事务回滚,即不添加新的用户信息。

2.2.2: @Transactional注意事项

当程序中有try-catch语句时,即使程序中有异常,事务也不会回滚。

java 复制代码
  @Transactional
    @RequestMapping("/insert")
    public Integer insert(UserInfo userInfo){
        if(userInfo==null||!StringUtils.hasLength(userInfo.getUsername())
        ||!StringUtils.hasLength(userInfo.getPassword())){
            return 0;
        }
        Integer integer = userService.addUserInfo(userInfo);
        System.out.println(integer);
        //搞一个算数异常
        try {
            int num=10/0;
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return integer;
    }

当在程序中,出现算数异常时,我们添加用户名wangwu和密码12345。

控制台代码:

数据库表:

从上述结果来看,发现添加上了,此时,事务并没有进行回滚。

如何解决?

解决方案一:将异常继续抛出,交给spring

解决方案二:

java 复制代码
   @Transactional
    @RequestMapping("/insert")
    public Integer insert(UserInfo userInfo){
        if(userInfo==null||!StringUtils.hasLength(userInfo.getUsername())
        ||!StringUtils.hasLength(userInfo.getPassword())){
            return 0;
        }
        Integer integer = userService.addUserInfo(userInfo);
        System.out.println(integer);
        //搞一个算数异常
        try {
            int num=10/0;
        } catch (Exception e) {
            System.out.println(e.getMessage());
            //使用代码,手动回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        return integer;
    }

三:事务的隔离级别

3.1:原子性

多个操作被打包成一个整体,要么全部都能够正确执行,要么就一个都不执行。

3.2:一致性

事务之前和事务之后,数据都能对上。


3.3:持久性

事务执行的各种操作,都是持久化存储在硬盘上的。(一旦事务执行成功,这里所有的操作,都是写在硬盘上的)


3.4:隔离性

并发执行事务的时候,隔离性,会在执行效率和数据可靠之间做出权衡。("隔离"描述的是同时执行的事务之间,相互的影响。隔离性越高,并发性越低,数据越可靠)

如果这两个事务,修改的是同一张表,这个时候存在麻烦。

由于上面的执行顺序可能存在差异,可能导致执行结果不同。


3.4.1:脏读

脏数据,是临时的,并非是最终的数据。

如何解决脏读?

3.4.2:不可重复读

在同一个读取事务中,可能会涉及到读操作,多个读操作,读到的数据不一样。

如何解决不可重复读?

3.4.3:幻读

一个事务在多次读的过程中,虽然读到的数据值是一样的,但是结果集不一样。

eg:第一次的记录是10条,第二次读的是11条记录。前十次记录是一样的,但是多出来一条。

如何解决幻读?

3.4.4:Spring事务隔离级别

Isolation.DEFAULT:以连接的数据库的事务隔离级别为主。

四:Spring事务传播机制

4.1:什么是事务传播机制?

Spring事务传播机制定义了多个包含事务的方法,相互调用时,事务是如何传递的。

当三个方法用同一个模式时,任何一个方法出问题了,都会进行事务的回滚操作。

三个方法用三种不同的模式,各个之间的方式不影响。

4.2:事务传播机制有哪些?

相关推荐
张小洛17 分钟前
Spring AOP 设计解密:代理对象生成、拦截器链调度与注解适配全流程源码解析
java·后端·spring·spring aop·aop
爱可生开源社区20 分钟前
SQLShift 重磅更新:支持 SQL Server 存储过程转换至 GaussDB!
数据库
GEEK零零七34 分钟前
Leetcode 1070. 产品销售分析 III
sql·算法·leetcode
贾修行43 分钟前
SQL Server 空间函数从入门到精通:原理、实战与多数据库性能对比
数据库·sqlserver
Wyc724091 小时前
SpringBoot
java·spring boot·spring
傲祥Ax1 小时前
Redis总结
数据库·redis·redis重点总结
一屉大大大花卷2 小时前
初识Neo4j之入门介绍(一)
数据库·neo4j
周胡杰2 小时前
鸿蒙arkts使用关系型数据库,使用DB Browser for SQLite连接和查看数据库数据?使用TaskPool进行频繁数据库操作
前端·数据库·华为·harmonyos·鸿蒙·鸿蒙系统
wkj0012 小时前
navicate如何设置数据库引擎
数据库·mysql
赵渝强老师2 小时前
【赵渝强老师】Oracle RMAN的目录数据库
数据库·oracle