Spring事务

一、什么是事务、事务的特性、事务的隔离级别

事务就是逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败。

事务具有四大特性(ACID),原子性(Atomomicity),一致性(Consistency),持久性(Isolation),隔离性(Durability)。不同的隔离级别总共可能产生三种问题脏读,不可重复度,幻读。

MySQL事务的隔离级别有四种read uncommited,read commited,repeatable read,serializable,MySQL默认是可重复读。读未提交三种问题都可能产生,读已提交可以解决脏读问题,但是解决不了不可重复读和幻读问题,可重复读可以解决前两种问题,串行化可以解决这三种问题。

二、Spring中事务实现

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

以向数据表删除记录为例

  1. 拿到JDBC事务管理器( DataSourceTransactionManager)对象
  2. 拿到事务定义(TransactionDefinition)对象
  3. 开启事务
  4. 插入数据库
  5. 提交事务/回滚事务
@RestController
@RequestMapping("/user0")
public class UserController0 {

    @Autowired
    private UserService userService;
    //1.创建JDBC事务管理器和事务定义对象
    @Autowired
    private DataSourceTransactionManager transactionManager;
    @Autowired
    private TransactionDefinition transactionDefinition;

    @RequestMapping("/del")
    public int del(Integer id) {
        if(id != null && id > 0) {
            //2.开启事务
            TransactionStatus transactionStatus =
                    transactionManager.getTransaction(transactionDefinition);
            //3.删除用户业务操作
            int result = userService.del(id);
            System.out.println("删除了: " + result);
            // 4.提交事务/回滚事务
//            transactionManager.commit(transactionStatus); //提交事务
            transactionManager.rollback(transactionStatus); //回滚事务
        }
        return 0;
    }
}
@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
    public int del(Integer id){
        return userMapper.del(id);
    }
}
@Mapper
public interface UserMapper {
    int del(@Param("id")Integer id);
}
<delete id="del">
    delete from userinfo where id=#{id}
</delete>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V3QfbG06-1692033441211)(F:\typora插图\image-20230814234320441.png)]

声明式事务:使用注解自动开启和提交事务

在方法/类上加@Transactinonal注解。

进入方法自动开启事务,执行完毕自动提交,发生异常自动回滚事务:

成功的情况:

@RestController
@RequestMapping("/user0")
public class UserController0 {

    @Autowired
    private UserService userService;

    @Transactional
    @RequestMapping("/del2")
    public int del2(Integer id) {
        if(id == null || id <= 0) {
            return 0;
        }
        return userService.del(id);
    }
}

对应的mapper和xml配置不用变,还是调用对象的service里的方法。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DB7FUvmp-1692033441211)(F:\typora插图\image-20230814235247719.png)]

报异常并回滚事务的情况:

这里人为加一个算数异常:

@Transactional
@RequestMapping("/del3")
public int del3(Integer id) {
    if(id == null || id <= 0) {
        return 0;
    }
    int result=0;
    result=userService.del(id);
    int num=10/0;
    System.out.println(result);
    return result;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MY8BwuSR-1692033441212)(F:\typora插图\image-20230815000553564.png)]

三、Spring事务隔离级别及设置方法

Spring事务默认级别就是对应连接数据的默认隔离级别

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S8NvdbLr-1692033441212)(F:\typora插图\image-20230815001115646.png)]

和MySQL的隔离级别含义基本一模一样。

通过Transactional的isolation属性设置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2xX3aif1-1692033441213)(F:\typora插图\image-20230815001410456.png)]

四、Spring的事务传播机制

多个事务进行嵌套调用的时,事务的执行行为叫做事务的传播机制。事务传播机制保证每个事务在多个调用方法间可控。

事务的传播机制一共分为三大类:支持当前事务,不支持当前事务和嵌套事务。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u16bXLyn-1692033441213)(F:\typora插图\image-20230815002158304.png)]

  1. 支持当前事务:以REQUIRED为例,一旦发生异常调用链上的所有事务全部回滚
  2. 不支持当前:以REQUIRED_NEW为例,
  3. 嵌套事务:嵌套事务可以回滚部分事务。(外部/主事务和内部/子事务)
    • 主事务提交成功,子事务也会被提交
    • 主事务回滚,子事务无论是否成功,一定回滚

Spring事务失效的情况

1.异常捕获处理

去掉try catch包裹

在之前的代码上边加try catch处理,再运行可以发现数据库的记录被删除,报错,事务失效

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qTn9JmLh-1692033441214)(F:\typora插图\image-20230815004728838.png)]

因为事务通知只有自己捕捉到了对应代码抛出的异常,才能进行回滚操作,这里如果自己处理了,事务没办法感知到。

2.非public修饰的方法

将方法设置成Public类型的

3.抛出受查异常

原因:spring默认只能回滚非受查异常。

解决办法:将@Transactional的rollbackFor属性设置为Exception.class

@Transactional注解

@Transactional使用方法:修饰类对类中所有public方法都生效,修饰方法对public方法生效。

参数说明:

参数作用
value当配置了多个事务管理器时,可使用该属性指定选择哪个事务管理器
transactionManager当配置多个事务管理器,可使用该使用指定选择哪个事务管理器
propagation事务的传播机制,默认值为Propagation.REQUIRED
isolation事务的隔离级别,默认值为Isolation.DEFAULT
timeout事务的超时时间,默认值为-1,如果超过该事件限制但事务还没完成,则自动回滚事务
readOnly指定事务是否为只读事务,默认值为false
rollbackFor用于指定能够触发事务回滚的异常类型,可以指定多个异常类型
rollbackForClassName用于指定能够触发事务回滚的异常类型,可以指定多个异常类型(字符串类型)
noRollbackFor不回滚抛出异常
noRollbackForClassName不回滚抛出异常(字符串类型)

说明

实际开发中,绝大部分时候会使用声明式事务,毕竟只需要加一个注解就可以实现想要的功能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值