事务
事务的四大特性:ACID 即原子性、一致性、隔离性、持久性
- 原子性: 当前事务的操作,要么同时成功,要么同时失败。原子性由undolog 来保证
- 一致性:使用事务的最终的目的,由其他三个特性以及业务代码正确逻辑来保证
- 隔离性:在事务并发执行的时候,他们内部的操作不能互相干扰,隔离性由Mysql的各种锁,以及MVCC机制来实现
- 持久性:一旦提交了事务,他对数据库的改变就应该是永久性的,持久性由redolog日志来实现。
事务的隔离级别
- 读未提交
- 读已提交
- 可重复读
- 串行化----底层同过读写锁互斥
MySQL默认的隔离级别是RR可重复读,但是一般会用RC 可重复读隔离级别下,当前事务读不到最新的数据,可能造成脏写
MVCC(多版本并发控制)可以做到读写不冲突,且可以避免类似脏读这样的问题,主要通过undolog版本连来实现。
普通的select操作就是快照读 insert,update,delete就是当前读
乐观锁:先比较再交换再设置值,不要在可重复度隔离级别使用
可重复读隔离级别解决了幻读,但是并没有完全解决,当在两次快照读之间插入了当前读的时候,还是会产生幻读的,这个时候就需要通过加间隙锁的方式来解决
读的时候是快照读---读历史数据。写的时候是当前读----读最新的数据
查询操作方法需要使用事务么?
看业务要求,和你使用的事务隔离级别,查找的结果集是什么? RR可重复读隔离级别,要实现可重复读的效果,方法又不加事务,那么多次查询方法就达不到可重复读的效果
出报表的业务场景,需要根据统一时间维度查询出来的数据做运算,就会出问题
传统的软件公司用RR隔离级别,出报表、erp各种OA系统 互联网公司用RC隔离级别,淘宝、拼多多等大型的互联网网站,这种情况用RC,读已提交隔离级别读操作可以不加事务,都是读已提交的数据
事务的优化
对于事务不要搞长事务大事务
- 并发情况下,数据库连接池容易被撑爆
- 锁定太多的数据,造成大量的阻塞和锁超时
- 执行时间长,容易造成主从延迟
- 回滚所需要的时间较长
- undo log 膨胀
- 容易导致死锁
RC隔离级别下,放到事务之内和之外都没区别,但是尽量放到事务之外 在一个方法里面进行查询操作,RR隔离级别需要放在事务之内
事务优化时间原则
- 将查询等数据准备操作放到事务之外
- 事务之间避免远程调用,远程调用需要避免超时,泛指事务等待时间太久
- 事务中避免一次性处理太多的数据,可以拆分成多个事务分次处理
- 更新等设计加锁的操作尽可能放到事务靠后的位置
比如下单的操作,先执行insert再执行update操作,因为如果先update的话,可能产生并发的问题,造成多个事务对同一条数据进行update操作,中间有个等待的过程,降低效率。而先执行insert操作的话,是往数据库中插入没有的数据,过程中不会有长时间的等待
- 能异步处理的尽量异步处理
异步也需要设置等待超时时间
- 应用侧(业务代码)保证数据一致性,非事务执行
如果对性能要求很高的话,可以不用事务,自己写代码保证数据的一致性,写try/catch,在catch里面做各种的业务判断。这种性能很高。但是开发起来太麻烦,不推荐