事务:数据一致性
事务特性:(ACID)
原子性:当前事务操作要么同时成功,要么同时失败。 由**undo log**日志实现
一致性:事务最终目的
隔离性:在事务并发执行时,他们内部的操作不能互相干扰,隔离性由**MySQL的各种锁以及MVCC机制**实现
持久性:一旦提交了事务,它对数据库的改变是永久性的。持久性由** redo log**日志实现
innoDB引擎:事务隔离级别
read uncommit(读未提交):脏读
read commit(读已提交):不可重复读
repeatable read(可重复读):幻读,(数据库有了快照)
serializable(串行):解决上面所有问题,包括脏写
set tx_isolation='read-uncommitted';
set tx_isolation='read-committed';
set tx_isolation='repeatable-read';
set tx_isolation='serializable';
查看当前数据库的事务隔离级别:show variables like 'tx_isolation';
设置事务隔离级别:set tx_isolation='REPEATABLE-READ';
Mysql默认的事务隔离级别是可重复读,用Spring开发程序时,如果不设置隔离级别默认用Mysql设置的隔离级别,如果Spring设置了就用已经设置的隔离级别
更新丢失或脏读:当两个或多个事务选择同一行数据修改,有可能发生更新丢失问题,即最后的更新覆盖了由其他事务所做的更新。
脏读:事务A读到了事务B已经修改但尚未提交的数据
不可重复读:事务A内部的相同查询语句在不同时刻读出的结果不一致
幻读:事务A读到了事务B提交的***新增***数据
脏写:
1、update account set balance = balance + 500 where id = 1;(悲观锁,行锁)
2、(2、乐观锁(+版本号)行锁)
MVCC(Mutil-Version Concurrency Control)多版本并发控制,就可以做到读写不阻塞,且避免了类似脏读这样的问题,主要通过undo日志链实现
select操作的是 快照读(历史版本)
insert,update和delete是 当前读(当前版本)(update和delete 加了行锁)
read commit(读已提交),语句级快照
repeatable read(可重复读),事务级快照
串行:
1、说明在串行模式下innodb的查询也会被加上行锁,如果查询的记录不存在会给这条不存在的记录加上锁(这种是间隙锁,后面会详细讲)。
2、如果客户端A执行的是一个范围查询,那么该范围内的所有行包括每行记录所在的间隙区间范围都会被加锁。
读锁(共享锁、S锁):select ... lock in share mode;
读锁是共享的,**多个事务可以同时读取同一个资源,但不允许其他事务修改**(串行化实现原理)
写锁(排他锁,X锁):select ... for update;
写锁是排他的,会阻塞其他的写锁和读锁,update\delete\insert都会加锁
多版本并发控制,(读写并行)
大事务的影响:
1、并发情况下,数据库连接池容易被撑爆
2、锁定太多的数据,造成大量的阻塞和锁超时(50s)
3、执行时间长,容易造成主从延迟
4、回滚所需要的时间比较长
5、undo log 膨胀
6、容易导致死锁
事务优化实践原则
1、将查询等数据准备操作放到事务之外
2、事务中避免远程调用,远程调用要设置超时,防止事务等待时间太久
3、事务中避免一次性处理太多数据,可以拆分成多个事务分次处理
4、更新等涉及加锁的操作尽可能放在事务靠后的位置(更新的会等待)
5、能异步处理的尽量异步处理
6、应用侧(业务代码)保证数据一致性,非事务执行
悲观锁(等上一个锁释放,再更新 update account set balance = balance+100 where id =1);
乐观锁(不会等锁,没有查到对应版本号再开启下一次where循环 update account set balance = 1000 where id = 1 and version = 1;)
间隙锁(3,10)
临建锁即包含了边界 边界加了锁(3,10]
MVCC(解决RR,RC读写同一份数据并发冲突问题)
当前读,快照读
数据可见性算法
RC隔离级别(每一次执行SQL查询语句会重新生成readView)
readView 当时时间点事务活跃状态
开启事务更新记录会有对应事务的版本链