Mysql 事务知识点与优化建议

事务

事务的隔离级别:

  • 读未提交
  • 读已提交
  • 可重复读
  • 串行化

事务的基本特性:

  • 原子性:靠Redo log来保证
  • 一致性:其他三个特性满足也就会满足一致性
  • 隔离性:靠锁、MVCC机制保证
  • 持久性:靠Undo log来保证

在可重复读隔离级别下可能会产生脏写/丢失更新的问题。如下:

事务A首先进行查询,并在java代码中对查询结果进行一些运算,还未执行后续的更新操作,事务还未提交。这时候事务B执行了update操作并提交事务。然后事务A再执行update 表名 set 字段名=java代码运算后的结果 where 。。。 这样就就会事务B执行的更新操作给覆盖掉,也就是脏写问题。

解决方法:

  • 不要在java代码中进行运算,直接在sql语句中进行,比如update 表名 set 字段名=字段名+100 where 。。。。。
  • 使用乐观锁方式,查询的时候先把version字段查询出来,然后在java代码中进行运行,在最后update操作时where条件加上version的条件。如果没有修改成功则使用循环操作进行重试,重新查询–> 更新 。

在可重复读隔离级别下,开启事务后,第一次select时,我们可以理解为这个时候当前事务保存了整个数据库的一个快照(当然底层不是使用快照 实际上是使用mvcc对进行更新操作后的各行数据都维护了版本链)。在这个事务中,即使其他数据表被其他事务更新了,我们在这个事务中读取的还是之前的数据。

在可重复读隔离界别下,有人说解决了幻读问题,有人说没有解决幻读问题。其实在可重复读隔离级别下没有完全解决幻读问题。

幻读:在一次事务中,第二次select操作读取到了其他事务新插入的数据。

原因是:在可重复读隔离级别下,select是快照读,更新操作是使用数据库中最新的数据做的更新。更新完成后再查询这条数据查询的结果也是最新的数据。但也仅仅只是这一行数据,其他数据读取的还是第一次select时的数据。

所以就会造成:在一个事务中,如果我们不对其他事务新增的数据做更新操作,在整个事务中我们是查询不到其他事务新增的数据,这也就是有些人说解决了幻读问题的原因。如果在一个事务中我们对其他事务新增的数据进行更新操作,我们这时再select是能查询出来其他事务新增的这条数据,这也就是没有完全解决幻读问题。

在串行化隔离界别下,就是以前我们学习读锁,写锁的思想了,在执行sql语句时会自动加上共享锁或者是排他锁,并造成读写互斥。但是其他三种隔离界别在select时不会加共享锁,仅仅是串行化隔离界别会加。

我们在使用InnoDB存储引擎时,在update时,它为什么是持久化Redo log文件到磁盘,而不是直接把脏页刷新写回磁盘。原因是因为Redo log是磁盘顺序写,效率要高。



大事务/长事务的影响:

  • 会造成其他事务长时间的等待
  • 并发情况下,数据库连接池容易被撑爆,因为上一个原因,其他事务从连接池中拿到了连接对象,但是一直阻塞,不能释放连接对象导致连接池爆满
  • 执行时间长,容易造成主从延迟
  • 回滚所需要的时间比较长
  • undo log膨胀
  • 容易导致死锁



事务优化:

  • 将查询等数据准备操作放到事务外 ,当然要业务允许,在读已提交隔离界别下就可以这样,但是在可重复读隔离界别下就不行
  • 事务中避免远程调用,远程调用要设置超时,防止事务等待时间太久
  • 事务中避免一次性处理太多数据,可以拆分成多个事务分次处理 ,当然也要业务允许才能用
  • 更新等涉及加锁的操作尽可能放在事务靠后的位置
  • 能异步处理的尽量异步处理
  • 应用侧(业务代码)保证数据一致性,非事务执行
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值