数据库事务和@Transaction注解的使用

4 篇文章 0 订阅

事务的基本要素

1. 原子性 :事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。

2. 一致性 :事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。

3. 隔离性 :同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。

4. 持久性 :事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。

有事务的产生就会有对应的解决方法 所以这时候就会产生事务的隔离级别来处理

产生的事务问题:

  1. 脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据 简单来说就是 事务A读到了事务B还没有提交的数据 例:银行取钱,事务A开启事务,此时切换到事务B,事务B开启事务–>取走100元,此时切换回事务A,事务A读取的肯定是数据库里面的原始数据,因为事务B取走了100块钱,并没有提交,数据库里面的账务余额肯定还是原始余额,这就是脏读 。

  2. 不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一致。 简单来说就是 在一个事务里面读取了两次某个数据,读出来的数据不一致 例 :事务A开启事务–>查出银行卡余额为1000元,此时切换到事务B事务B开启事务–>事务B取走100元–>提交,数据库里面余额变为900元,此时切换回事务A,事务A再查一次查出账户余额为900元,这样对事务A而言,在同一个事务内两次读取账户余额数据不一致,这就是不可重复读。

  3. 幻读:在一个事务里面的操作中发现了未被操作的数据 例:事务A开启事务–>修改所有学生当天签到状况为false,此时切换到事务B,事务B开启事务–>事务B插入了一条学生数据,此时切换回事务A,事务A提交的时候发现了一条自己没有修改过的数据,这就是幻读,就好像发生了幻觉一样。幻读出现的前提是并发的事务中有事务发生了插入、删除操作。

事务的隔离级别:

事务隔离级别越高,在并发下会产生的问题就越少,但同时付出的性能消耗也将越大,因此很多时候必须在并发性和性能之间做一个权衡
1,DEFAULT
默认隔离级别,每种数据库支持的事务隔离级别不一样,如果Spring配置事务时将isolation设置为这个值的话,那么将使用底层数据库的默认事务隔离级别。MySQL,可以使用"select @@tx_isolation"来查看默认的事务隔离级别

2,读未提交(read-uncommitted):即能够读取到没有被提交的数据,脏读 幻读 不可重复读 都不能解决 因此很少使用

3,读已提交(read-committed): 即能够读到那些已经提交的数据,自然能够防止脏读,但是无法限制不可重复读和幻读

4,可重复读(repeatable-read):即在数据读出来之后加锁,类似"select * from XXX for update",明确数据读取出来就是为了更新用的,所以要加一把锁,防止别人修改它。REPEATABLE_READ的意思也类似,读取了一条数据,这个事务不结束,别的事务就不可以改这条记录,这样就解决了脏读、不可重复读的问题,但是幻读的问题还是无法解决

5,串行化(serializable):最高的事务隔离级别,不管多少事务,挨个运行完一个事务的所有子事务之后才可以执行另外一个事务里面的所有子事务,这样就解决了脏读、不可重复读和幻读的问题了

注释 :不是事务隔离级别设置得越高越好,事务隔离级别设置得越高,意味着势必要花手段去加锁用以保证事务的正确性,那么效率就要降低,因此实际开发中往往要在效率和并发正确性之间做一个取舍,一般情况下会设置为READ_COMMITED,此时避免了脏读,并发性也还不错

MySQL查看和修改事务隔离级别的几个命令:

1,查看事务隔离级别使用select @@tx_isolation

2.修改当前会话事务隔离级别使用SET session TRANSACTION ISOLATION LEVEL Serializable;(参数可以为:Read uncommitted|Read committed|Repeatable read|Serializable)

3,修改全局事务隔离级别使用SET global TRANSACTION ISOLATION LEVEL Serializable;(参数可以为:Read uncommitted|Read committed|Repeatable read|Serializable)
修改了会话的事务隔离级别,比如MyBatis,getSqlSession()的时候,只针对这一次拿到的Session有效
修改了全局的事务隔离级别,那么针对此后所有的会话有效,当前已经存在的会话不受影响。

Spring的@Transaction注解:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
    // 通过 bean name 指定事务管理器
    @AliasFor("transactionManager")
    String value() default "";
    // 同 value 属性
    @AliasFor("value")
    String transactionManager() default "";
    // 传播行为
    Propagation propagation() default Propagation.REQUIRED;
    // 隔离级别
    Isolation isolation() default Isolation.DEFAULT;
    // 超时时间
    int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
    // 是否只读事务
    boolean readOnly() default false;
    // 方法在发生指定异常时回滚,默认是所有异常都囚滚
    Class<? extends Throwable>[] rollbackFor() default {};
    // 方法在发生指定异常名称时回滚,默认是所有异常都回滚
    String[] rollbackForClassName() default {};
    // 方法在发生指定异常时不回滚,默认是所有异常都回滚
    Class<? extends Throwable>[] noRollbackFor() default {};
    // 方法在发生指定异常名称时不回滚,默认是所有异常都回滚
    String[] noRollbackForClassName() default {};
}

例:回滚的使用

// 代码报错出现 Exception的级别以及以下子类的错误 就会回滚
   @Transactional(rollbackFor = Exception.class)
    public void addReturnOrder(Long id, Integer isback, List<String> listString, User user) {
    
    }
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

罗小稳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值