阅读 147

MySQL笔记:事务和隔离级别(纯理论)

事务和隔离级别

1. 事务

事务是数据库并发操作中,最小的控制单元。保证了一组数据库操作,要么全部成功,要么失败。

事务在引擎层实现。有的引擎支持事务,如InnoDB,有的引擎不支持,如MyISAMMemory。通常情况下,记住这三个引擎即可。

ACID

  • 原子性(Atomicity):一个事务中的所有操作,要么全部成功,要么全部失败,不会结束在某个中间环节。

  • 一致性(Consistency):事务结束以后,数据库完整性没有被破坏,即符合预设的业务规则。

  • 隔离性(Isolation):允许多个并发事务对数据进行读写、修改。

  • 持久性(Durability):事务结束后,事务的所有操作都被持久化到数据库。

启动方式

  • 使用begin或者start transaction显示启动事务,使用commit提交事务,使用rollback回滚事务。

  • 使用set autocommit=0取消自动提交,之后任意语句都会开启一个事务,并且不会自动提交,需要执行commit或者rollback

使用set autocommit可能导致意外长事务。

如果不想每次都执行begin,可以使用commit work and chain,表示提交本事务后,自动开启下一个事务。

并发事务问题

多个事务并发执行时,可能出现一些并发问题:(假设有两个事务T1T2

  • 脏读:如果T1读取了被T2更新但还没被提交的字段,如果T2回滚,T1之前读取到的内容就是无效的。

  • 不可重复读:T1事务过程中读取了一个字段,然后T2更新了该字段,T1之后再次读取到的值就会变化。

  • 幻读:T1从一个表中,根据某些条件读取出一些记录,然后T2向该表插入新纪录,T1再次读取时,会把新纪录也读出来。

2. 隔离级别

隔离级别被用于解决事务的并发问题。

分类

  • 读未提交:一个事务还没提交时,它做的变更就能被别的事务看到。

  • 读提交:一个事务提交之后,它做的变更才会被其它事务看到。

  • 可重复读:一个事务执行过程中看到的数据,总是跟它启动时看到的数据一致。

  • 串行化:对同一行记录,”写“会加”写锁“,读会加”读锁“。

写锁是排他锁,即S锁;读锁是共享锁,即X锁。

Oracle默认的隔离级别是读提交。

MySQL默认的隔离级别是可重复读。

以下讨论,假定是处于可重复读隔离级别下。

查看隔离级别

MySQL查看隔离级别的命令:

# 某些版本使用 tx_isolation
select @@global.tx_isolation;
# 某些版本使用 transaction_isolation
seelct @@global.transaction_isolation;
复制代码

3. 视图

隔离级别通过视图来实现。

可重复读隔离级别下,视图是在事务启动时创建的,整个事务存在期间都用这个视图。

读提交级别下,视图是在每个SQL语句开始执行时创建的。

读未提交级别下,直接返回记录上的最新值,没有视图概念。

串行化级别下,通过直接加锁的方式避免并行访问。

回滚日志

每条记录更新时,都会记录一条回滚日志。通过回滚日志,可以得到前一个状态的值。

MVCC

同一条记录在系统中可以存在多个版本,这就是版本并发控制(MVCC)。

不同时刻启动的事务有不同的视图,视图结合回滚日志实现数据的版本并发控制。

当没有事务需要用到这些回滚日志时,即没有比这个回滚日志更早的视图,回滚日志会被清除。

不要使用长事务

长事务提交前,它可能用到的回滚日志都必须保留,会占用大量存储空间。

MySQL5.5及以前的版本,回滚日志跟数据字典一起放在ibdata文件里,即使回滚段被清除,文件也不会变小。

长事务会占用锁资源,会拖垮整个库。

查询长事务

查询持续时间超过60的长事务:

select * from information_schema.innodb_trx where TIME_TO_SEC(TIMEDIFF(now(), trx_started)) > 60;
复制代码
文章分类
后端
文章标签