MySQL中的事务特性
type
status
date
slug
summary
tags
category
icon
password
事务
事务就是以可控的方式对数据资源进行访问的一组操作。为了保证事务执行前后,数据资源所承载的系统状态始终处于“正确”状态,事务本身持有4个限定属性,原子性(
Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability),这也就是常说的事务的ACID属性。原子性(Atomicity)
一个事务包含多个操作,这些操作要么全部执行,要么全都不执行。实现事务的原子性,要支持回滚操作,在某个操作失败后,回滚到事务执行之前的状态。
回滚实际上是一个比较高层抽象的概念,大多数
DB在实现事务时,是在事务操作的数据快照上进行(比如MVCC),并不修改实际的数据,如果有错并不会提交,所以自然的支持回滚。而在其他支持简单事务的系统中,不会在快照上更新,而直接操作实际数据。可以先预演一遍所有要执行的操作,如果失败则这些操作不会被执行,通过这种方式很简单的实现了原子性。
一致性(Consistency)
一致性是指事务使得系统从一个正确的一致性的状态转换到另一个正确的一致性状态。
这里我们举个大家都在说的财务系统的例子.
A要向B支付100元,而A的账户中只有90元,并且我们给定账户余额这一列的约束是,不能小于0.那么很明显这条事务执行会失败,因为90-100=-10,小于我们给定的约束了.
这个例子里,支付之前我们数据库里的数据都是符合约束的,但是如果事务执行成功了,我们的数据库数据就破坏约束了,因此事务不能成功,这里我们说事务提供了一致性的保证.然后我们再看个例子
A要向B支付100元,而A的账户中只有90元,我们的账户余额列没有任何约束.但是我们业务上不允许账户余额小于0.因此支付完成后我们会检查A的账户余额,发现余额小于0了,于是我们进行了事务的回滚.
这个例子里,如果事务执行成功,虽然没有破坏数据库的约束,但是破坏了我们应用层的约束.而事务的回滚保证了我们的约束,因此也可以说事务提供了一致性保证(ps:事实上,是我们应用层利用事务回滚保证了我们的约束不被破坏).最后我们再看个例子
A要向B支付100元,而A的账户中只有90元,我们的账户余额列没有任何约束.然后支付成功了.
这里,如果按照很多人的理解,事务不是保证一致性么?直观上账户余额为什么能为负呢.但这里事务执行前和执行后,我们的系统没有任何的约束被破坏.一直都是保持正确的状态.
所以,综上.你可以理解一致性就是:应用系统从一个正确的状态到另一个正确的状态.而
ACID就是说事务能够通过AID来保证这个C的过程.C是目的,AID都是手段.隔离性(Isolation)
ISOLATION LEVEL | Dirty Read | Non-Repeatable Read | Phantom Read |
READ UNCOMMITED | 可以出现 | 可以出现 | 可以出现 |
READ COMMITED | 不允许出现 | 可以出现 | 可以出现 |
REPEATABLE READ | 不允许出现 | 不允许出现 | 可以出现 |
SERIALIZABLE | 不允许出现 | 不允许出现 | 不允许出现 |
- Read Uncommitted
该隔离级别的事务会读到其它未提交事务的数据,此现象也称之为脏读。
准备两个终端先创建一个数据库和一张简单的表;
创建终端一 开启事务把
test表中id改为2创建终端二 开启事务去查看
test表中的记录在终端二中读取到了终端一中未提交的事务,就是产生了脏读大部分业务场景中都不允许脏读的出现,但是此隔离级别下数据库的并发是最好的。
- Read Committed
一个事务可以读取另一个已提交的事务,多次读取会造成不一样的结果,此现象称为不可重复读问题,
Oracle 和 SQL Server 的默认隔离级别。还是拿上面个
test表连接两个终端,终端一开启事务修改test表id字段为3启动终端二开启事务,查看
test表中的数据继续操作终端一
继续操作终端二
终端二在开启一个事务之后,在第一次读取
test表时(终端一的事务还未提交时)ID=2,在第二次读取test表(终端一的事务已经提交时)ID = 3说明在此隔离隔离级别下可以读取到已提交的事务。- Repeatable Read
该隔离级别是
MySQL 默认的隔离级别,在同一个事务里,select 的结果是事务开始时时间点的状态,因此,同样的 select 操作读到的结果会是一致的,但是,会有幻读现象。MySQL 的 InnoDB 引擎可以通过 next-key locks 机制来避免幻读。首先准备一个
test数据库和一张简单test表两个连接数据库的终端终端一开启一个事务
终端二开启一个事务
操作终端一执行操作事务并提交
操作终端二查询
test表由于终端二是看不见终端一已经提交的事务那么操作终端二继续执行
id=1的insert操作我去用终端二去查询时发现表里明明没数据啊那为什么给我报主键冲突的报错呢!这就是该隔离级别下会产生的问题幻读。
- Serializable
在该隔离级别下事务都是串行顺序执行的,
MySQL 数据库的 InnoDB 引擎会给读操作隐式加一把读共享锁,从而避免了脏读、不可重读复读和幻读问题。首先准备一个简单的库和简单的一张表和两个连接终端
操作终端一开启事务向
test表写入一条记录操作终端二开启事务查询
test表操作终端一提交事务
一旦事务提交终端二会立马返回
ID=1的记录,否则会一直卡住,直到超时其中超时参数是由innodb_lock_wait_timeout控制由于每条select语句都会加锁,所以该隔离级别并发能力最弱,但是该结论不一定。持久性(Durability)
事务一旦提交,则其结果就是永久性的。即使发生宕机的故障,数据库也能将数据恢复,也就是说事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。这只是从事务本身的角度来保证,排除
RDBMS(关系型数据库管理系统,例如 Oracle、MySQL 等)本身发生的故障。注:MySQL 使用
redo log 来保证事务的持久性。Loading...