点击上方“IT那活儿”公众号,关注后了解更多内容,不管IT什么活儿,干就完了!!!
从事数据库开发和运维的人员或多或少都了解过关于《可重复读和读提交》这2种隔离级别,今天我们就来研究一下。
一般来说事务存在4大特性ACID(原子性、一致性、隔离性、持久性),这里我们主要来说一下隔离性。当多个事务并发执行时,数据库为了保证事务之间的隔离性便引入了隔离级别的概念。SQL标准将事务隔离级别分为读未提交(read uncinnutted),读已提交(read committed/RC),可重复度(repeatable read/RR),串行化(serializable)。
表格中读未提交与串行化比较简单,也不常用。目前主流数据库采用的主要是读已提交和可重复度。分别来看一下,在T3时刻,可重复读级别下,虽然T2时刻其他事务已提交变更,但是事务任然以启动时间T1为准,也就是查询结果需要与T1保持一致,即T2事务属于未来事务,不可见。而在读已提交级别下以当前语句时刻为准,对于T3时刻而言,T2时刻属于已提交事务,即可获取T2时刻已提交的变更。这里我们可以发现2种隔离级别主要区别在于事务起点时刻的划分,也可以称为数据库快照(简单理解就是数据库某一时刻的全局事务状态)的划分。对于数据库任意时刻的快照而言总是存在如下3种情况:对于快照n而言未提交的事务总是不可见。
快照n之后,其他事务x做的提交,这里包含快照n之前启动在n之后完成提交的事务也包含快照n之后新启动完成提交的事务,对于快照n而言在其之后提交的事务都属于未来事务,同样不可见。
快照之前已完成提交的事务才可见。
也就是说对于可重复读级别而言快照以事务开始时间为准,读已提交级别下每条SQL语句启动时重新获取当前数据库的快照以便获取最新已提交的事务情况。这里可能有些同学会有疑问,在RR级别下,T3时刻将T减1是不是意味着T2时刻的事务变更会丢失?针对这个问题,数据库引擎当然没有那么小白,这里适用一条新的规则, 发生DML时,需要读取已提交事务的最新值,这个读一般称为"当前读"(current read)。案例中也就是T3发起set DML时需要获取已提交的最新值也就是T=2后,再进行运算,这就不存在事务丢失的风险了,需要注意如果事务n进行了修改但是没有提交,这里事务1就会产生行锁等待,这里我们就不再展开介绍了。
4.1 RC:适用于CRM类查询相对较多,需要获取最新值类系统。查询与修改7:1,8:1等等,注意具体参考实际系统,并不绝对。4.2 RR:适用于对账类系统,比如信用卡账户表与信用卡消费明细表。采取RC隔离级别时,如果不将数据静止化,对账的事务周期内,账户表余额或明细表一直发生变更,那整个账本永远也无法对账一致。另外比如mysqldump之类的逻辑备份,使用--single-transaction时自动设置会话事务为RR,其不仅仅是备份出数据,同样需要保证数据与数据之间的逻辑一致性。