数据库事务要满足ACID:
- Atomicity原子性
- consistency一致性
- isolation隔离性
- durability持久性
事务的隔离级别:
- 读未提交
- 出现问题:脏读
- 读提交
- 问题:不可重复读
- 可重复读
- 问题:幻读
- 串行化
MySQL默认隔离级别是可重复读,而Oracle的默认隔离级别是读提交。
1.1. MySQL是如何保证可重复读的?
确切的说是InnoDB,如何实现可重复读事务的。
MVCC(数据库多版本并发控制),通过多个版本号来控制。
也就是说每一个修改都会对应多个回滚版本号。
通过版本号来控制这一时刻下,类似于静态数据。(todo这里后面有讲到是使用什么来做到版本控制的)
MySQL不可能将所有的版本日志都记录下来,这样实在太浪费空间了。
那么MySQL什么时候删除日志?
在不需要的时候删除,MySQL会自行判断,当没有事务用到此回滚日志时,就会删除。
由此便引出一个主意点:
- 避免长事务
- 如何避免长事务?
- 很多时候长事务,其实是隐形发生的,并不是估计为之,误用导致。
- 开启事务的方式
- 显示启动事务语句,begin或者start transaction。需要显示的commit,回滚rollback。
set autocommit=0
,自动提交会被关掉。只要执行一个select语句就会开启一个事务,并且不会自动commit,事务会一直存在,直到手动commit或者rollback语句,或者断开连接。
有些客户端会在连接成功时,自动设置set autocommit=0
,会导致接下来的查询都在一个长事务当中。
建议使用方式:
- 总是设置
set autocommit=1
显示语句开启事务,必须使用begin与commit或者rollback语句对来处理事务。 - 如果频繁使用事务,可以使用
commnit work and chain
语法,在一个事务commit之后,会自动开启下一个事务。 - 监控
information_schema.innodb_trx
表,发现长事务就要立刻警报select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60
1.2. 注意:MySQL默认可重复读但是还是会出现幻读
1.2.1. 什么是幻读?
也是可重复读的特性导致。
1.2.2. 如何解决幻读?
select * from test for update
- 行级排他锁
select * from test lock in share mode
- 行级共享锁
- 注意可能会发生死锁
1.2.2.1. select for update