您的位置:首页 > 数据库 > MySQL

闲话MVCC

2015-10-14 01:28 513 查看

为什么需要事务

其实和我们需要
是一个道理。因为我们业务上的一个逻辑操作单元Tx_A,对应的是多个计算机指令。我们需要一种机制来确保在Tx_A操作执行期间,其内部状态不可以被外界观测到。如果外界访问,要么阻塞等待直到该操作结束。要么直接返回告诉它,“Sorry ,I’m busy now”。事务就是这样一种机制。做数据库的大神说,“得了,您也别自己去实现这样一种机制了,就我实现得了。你们会用就行,免得一大堆bug”,所以事务的出现使得我们能更好focus在我们的业务上。而不用自己去实现事务等价一套APIs。

事务是一个说明性的概念,这个概念用来表述你想要达到什么样的效果。

Mysql对外暴露的事务APIs如下:

1.事务的开始

START TRANSACTION

BEGIN

2.事务提交

COMMIT

3.事务回滚

ROLLBACK

ANSI/ISO isolation(隔离级别)

一言以蔽之,隔离级别是事务之间可见性的定义。

1. 可序列化(Serializable)

可序列化涉及到范围锁(主要是用于解决聚集查询),所以没有幻读问题。

2.可重复读(READ-REPEATABLE)

在可重复读取(REPEATABLE READS)级别下,数据库系统会在整个事务期间保持读取锁写入锁。但相较于可序列化,范围锁不会持有,所以幻读可能会出现。

Ps:MySQL的MVCC兼容此隔离级别,并且避免了幻读问题。

3.不可重复读(READ-COMMITTED)

在READ COMMITTED级别下,整个事务期间保持写入锁,但读取锁会在SELECT执行之后立即释放。所以也称为NON-REPEATABLE READ。

4.读未提交(READ-UNCOMMITED)

在此隔离级别下,脏读可能会出现。

Ps:此处需要注意脏读含义的理解。

事务A如果可以看见其它事务的中间状态,那么就是脏读。换句话说,一个事务能看见的数据,要么在其它事务开始之前,要么是之后。事务是将数据库状态从某个一致的状态,变成另一种一致的状态。

小结

以MySql为例,大多数应用采用的隔离级别为
REPEATABLE READ
,所以SELECT读到的数据可能不是目前最新的(可见性?)。其实对大多数业务来说都OK,因为大多数业务并不要求全局的happen-before关系,而只要求某几个操作之间有。

MVCC

以隔离级别「READ-REPEATABLE」为例,按照上面「读写锁」的实现,那么读写依然是冲突的,能不能达到读写也不冲突呢?毕竟人类对性能的追求是无止境的。答案是肯定的。其思想上和Java的
CopyOnWriteArrayList
极为类似。简单来说

就是通过”volatile+写锁”实现。这样就可以实现

读写不互斥(通过volatile);

还是以经典的Bob给Simith转账100刀为例.

事务A

start

update account set balance=balance where id=’bob’ and balance >=100

commit;

事务B

start;

select balance where id=’bob’

commit;

现在假设事务A和事务B并行执行,照例说事务B,应该会等事务A提交时候( 提交会释放锁),之后才会读到bob账户余额,事实上由于读余额时,并不会尝试获取写锁,所以无需等待。所以读写不互斥。

Ps:肯定有同学会疑惑,这样不就是读得不是最新的了嘛?的确,这样读到的数据不是最新的,但是为什么需要读到最新的呢,对大多读事务场景,并不需要读到最新值啊,如果是写事务的话,那么对业务属性是否满足更新条件,必须放在update的where子句中,而不能先select后update,当然,对大多数应用,先selelct 如果(不)满足,然后(不)更新,如果大多数条件都不用更新,那么这么写,可能会有性能优化,毕竟select 无锁,update可是必须要锁的。

显示锁

隐式锁

select 隐式获取与释放读锁

写时复制(COW(Copy-On-Write))的

参考资料

關係數據庫的事務隔離、鎖定與並發控制

海量数据-事务一致性2
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  mysql mvcc