@lambeta
2016-07-30T15:11:58.000000Z
字数 2116
阅读 360
concurrency事务是一组不可分割的SQL query语句,或者说是一个最小的工作单元。
在阅读《Java虚拟机并发编程》(Programming Concurrency on the JVM - Materning Synchronization, STM and Actors)中STM(Software Transaction Memory)时,我看到transaction特征在concurrency中的神奇应用场景:
我看到了很多STM的好处,但是看到处理写偏斜异常(Handling Write Skew Anomaly)(可以简单理解为两个事务修改的变量不是同一个,但是两个变量之间又有约束关系)一章时,作者使用ensure函数给约束变量加了读锁。加读锁的意义在于本事务之外,其他事务无法获得该变量的写锁,自然无法修改它的值。但是这里显式地使用了锁,所以可以明确事务不是锁无关的,而且这让我联想到了数据库事务隔离级别中的可重复读(REPEATABLE_READ)。可重复读也是使用在特定记录行上使用读锁,来防止外部事务修改了该条记录行。
有趣的事情来了,事务原子性能确保数据的完整性,而事务的一致性和隔离性则侧重于数据的可见性。可见性的保证在并发当中绝对和锁相关。我刚说了,事务给锁提供了抽象屏障,而且事务的隔离级别依旧仰仗锁的粒度,所以不要将事务看做银弹,以为有了事务,锁就不值一提。
一直被《高性能MySQL》里的解释弄得稀里糊涂,纠结于脏读、不可重复读和幻读之间的关系。而且某些解释看似合理,但完全没有指导价值。比如:阐述隔离级别,却没法从中得出我们如何结合应用场景选择合适的隔离级别。
SELECT USER.age into age FROM USERS name='YOU'; UPDATE SET name='ME' WHERE name='YOU';并提交。那么这时候,age是无效的状态,你再拿来用就有问题了。这一级别适合于读多写少且写偏斜不存在的场景。幻读
可重复读级别无法防止幻读。幻读是这样一种场景,本事务读取一个范围内,范围内,范围内(重要的事情写三遍)的数据集,但是另一事务又向这个范围内插入一条记录,导致数据集发生变化了,像是出现了幻觉,所以称为幻读(我很痛恨一些奇葩的科学家起的不合理的名字,这就是其一。按着这种逻辑,不可重复读不也可以说是出现幻觉吗?)。那么为什么会出现这种情况,原因是新插入的记录以前不存在于数据库中,所以你没法为它加锁。而且可重复读只是为每行记录加锁,没有用到Rang Lock,这一幻影插入操作总能成功。
不过MySQL中InnoDB存储引擎提供了MVCC(多版本并发控制)技术,为每条记录设置一个递增的事务编号,大于本次事务编号的记录,不准插入记录。
可重复读+MVCC即可解决并发中的大部分问题。
Serializable Read
顾名思义,串行读,事务之间是串行的,同步的。换言之,并发性剧减。
描述的是事务本身的属性
- readOnly:所有的操作都是读取操作,不涉及任何产生副作用的操作。