1、事务特性
原子性
一致性
隔离性
持久性
2、多事务同时执行时会出现的问题
脏读
当前事务读到的数据是别的事务想要修改成为的但是没有修改成功的数据。
不可重复读
当前事务先进行了一次数据读取,然后再次读取到的数据是别的事务修改成功的数据,导致两次读取到的数据不匹配,也就照应了不可重复读的语义。
(针对update或delete)
幻读
当前事务读第一次取到的数据比后来读取到数据条目少。
(针对insert)
3、如何解决幻读?
产生原因
行锁只能锁住行,但是新插入记录这个动作,要更新的是记录之间的“间隙”
解决方法
间隙锁 (Gap Lock),RR级别下生效
4、事务隔离级别
读未提交
一个事务还未提交,它所做的变更就可以被别的事务看到
读提交RC
一个事务提交之后,它所做的变更才可以被别的事务看到
可重复读RR
一个事务执行过程中看到的数据是一致的。未提交的更改对其他事务是不可见的
(InnoDB默认隔离级别)
串行化
对应一个记录会加读写锁,出现冲突的时候,后访问的事务必须等前一个事务执行完成才能继续执行。
5、配置方法
启动参数transaction-isolation。
6、事务隔离的实现
每条记录在更新的时候都会同时记录一条回滚操作。同一条记录在系统中可以存在多个版本,这就是数据库的多版本并发控制(MVCC)。
7、回滚日志什么时候删除?
系统会判断当没有事务需要用到这些回滚日志的时候,即系统里没有比这个回滚日志更早的read-view的时候,回滚日志会被删除。
8、为什么尽量不要使用长事务?
长事务意味着系统里面会存在很老的事务视图,在这个事务提交之前,回滚记录都要保留,这会导致大量占用存储空间。除此之外,长事务还占用锁资源,可能会拖垮库。
9、事务启动方式
- 显式启动事务语句,begin或者start transaction,提交commit,回滚rollback。
- set autocommit=0,该命令会把这个线程的自动提交关掉。这样只要执行一个select语句,事务就启动,并不会自动提交,直到主动执行commit或rollback或断开连接。
10、InnoDB 在实现 MVCC 时用到的一致性读视图,即 consistent read view,用于支持 RC(Read Committed,读提交)和 RR(Repeatable Read,可重复读)隔离级别的实现。
11、事务在启动时会拍一个快照,这个快照是基于整个库的,即整个库的修改对于该事务都是不可见的(对于快照读的情况),如果在事务内select t表,另外的事务执行了DDL t表,根据发生时间要么锁住要么报错。
12、事务如何实现MVCC(多版本并发控制)
(1)每个事务都有一个事务ID,叫做transaction id(严格递增)
(2)事务在启动时,找到已提交的最大事务ID记为up_limit_id。
(3)事务在更新一条语句时,比如id=1改为了id=2.会把id=1和该行之前的row trx_id写到undo log里,
并且在数据页上把id的值改为2,并且把修改这条语句的transaction id记在该行行头。
(4)再定一个规矩,一个事务要查看一条数据时,必须先用该事务的up_limit_id与该行的transaction id做比对,
如果up_limit_id>=transaction id,那么可以看.如果up_limit_id<transaction id,则只能去undo log里去取。去undo log查找数据的时候,也需要做比对,必须up_limit_id>transaction id,才返回数据
13、什么是当前读
由于当前读都是先读后写,只能读当前的值,所以为当前读.会更新事务内的up_limit_id为该事务的transaction id。
14、为什么RR能实现可重复读而RC不能
快照读的情况下,RR不能更新事务内的up_limit_id,
而RC每次会把up_limit_id更新为快照读之前最新已提交事务的transaction id,则RC不能可重复读;
当前读的情况下,RR是利用record lock+gap lock来实现的,而RC没有gap,所以RC不能可重复读。
——整理自丁奇老师专栏《MySQL实战45讲》