oracle也是会发生写偏斜的,读写偏斜现象的初学者指南

介绍

在关于ACID和数据库事务的文章中,我介绍了SQL标准描述的三种现象:

脏读

不可重复读

幻读

尽管这些可以很好地区分四个隔离级别(未提交读,已提交读,可重复读和可序列化),但实际上,还有更多的现象需要考虑。 1995年的论文(《 ANSI SQL隔离级别批判》)介绍了标准规范中省略的其他现象。

在我的《高性能Java持久性》一书中,我决定坚持“事务”一章,因为它对数据访问的有效性和效率都非常重要。

领域模型

对于以下示例,我将使用以下两个实体:

ef3b2e5a43987acd5b491b20a03480b1.png

在我们的虚构应用程序中,更改“ 帖子”标题后,必须将作者记录在关联的“ PostDetails”记录中。 如果未防止读写时滞,则可以破坏此域模型约束,如以下测试案例所示。

读取歪斜

以下测试模拟了读取偏斜如何发生:

doInConnection(aliceConnection -> {

prepareConnection(aliceConnection);

String title = selectStringColumn(

aliceConnection,

selectPostTitleSql()

);

executeSync(() -> {

doInConnection(bobConnection -> {

prepareConnection(bobConnection);

try {

update(

bobConnection,

updatePostTitleParamSql(),

new Object[]{"Bob"}

);

update(

bobConnection,

updatePostDetailsAuthorParamSql(),

new Object[]{"Bob"}

);

} catch (Exception e) {

LOGGER.info("Exception thrown", e);

preventedByLocking.set(true);

}

});

});

String createdBy = selectStringColumn(

aliceConnection,

selectPostDetailsAuthorSql()

);

});

爱丽丝选择一个帖子标题

Bob潜入并更新了Post和PostDetails实体

Alice线程将继续,并且她选择PostDetails记录

如果允许读取偏斜,则Alice会看到Bob的更新,并且可以假定先前的Post版本(在交易开始时读取)是Bob发行的(可能不准确)。

在四个最常见的关系数据库系统上运行此测试可获得以下结果:

数据库隔离级别

读取歪斜

Oracle读已提交

Oracle可序列化

没有

SQL Server读未提交

SQL Server读取已提交

SQL Server读取提交的快照隔离

SQL Server可重复读取

没有

SQL Server可序列化

没有

SQL Server快照隔离

没有

PostgreSQL读未提交

PostgreSQL读已提交

PostgreSQL可重复读

没有

PostgreSQL可序列化

没有

MySQL读取未提交

MySQL读取提交

MySQL可重复读

没有

MySQL可序列化

没有

写偏斜

要模拟写偏斜,您需要执行以下测试用例:

doInConnection(aliceConnection -> {

prepareConnection(aliceConnection);

String title = selectStringColumn(

aliceConnection,

selectPostTitleSql()

);

String createdBy = selectStringColumn(

aliceConnection,

selectPostDetailsAuthorSql()

);

executeSync(() -> {

doInConnection(bobConnection -> {

prepareConnection(bobConnection);

try {

String bobTitle = selectStringColumn(

bobConnection,

selectPostTitleSql()

);

String bonCreatedBy = selectStringColumn(

bobConnection,

selectPostDetailsAuthorSql()

);

update(

bobConnection,

updatePostTitleParamSql(),

new Object[]{"Bob"}

);

} catch (Exception e) {

LOGGER.info("Exception thrown", e);

preventedByLocking.set(true);

}

});

});

update(

aliceConnection,

updatePostDetailsAuthorParamSql(),

new Object[]{"Alice"}

);

});

爱丽丝从PostDetails记录中选择Post标题和作者

Bob还选择了Post标题和相关的作者,但他决定仅更新标题

爱丽丝想在不更改帖子标题的情况下更新PostDetails记录

如果允许写偏斜,则将执行Alice和Bob不相交的写操作,而不会受到控制这两个记录的约束的阻止。

在四个最常见的关系数据库系统上运行此测试可获得以下结果:

数据库隔离级别

写偏斜

Oracle读已提交

Oracle可序列化

SQL Server读未提交

SQL Server读取已提交

SQL Server读取提交的快照隔离

SQL Server可重复读取

没有

SQL Server可序列化

没有

SQL Server快照隔离

PostgreSQL读未提交

PostgreSQL读已提交

PostgreSQL可重复读

PostgreSQL可序列化

没有

MySQL读取未提交

MySQL读取提交

MySQL可重复读

MySQL可序列化

没有

写偏斜在多版本并发控制机制中很普遍,即使声称使用“可序列化”,Oracle也无法阻止它,而实际上它只是一个快照隔离级别。

当使用“可重复读”和“可序列化”时,SQL Server默认的基于锁定的隔离级别可以防止写偏斜。 快照隔离级别(基于MVCC)中的任何一个都不能阻止/检测到它。

PostgreSQL使用更高级的可序列化快照隔离级别来阻止它

MySQL在使用Serializable时会使用共享锁,因此即使InnoDB也是基于MVCC的,也可以防止写偏斜

如果您对此主题感兴趣,那么您也可以阅读我正在编写的《 高性能Java持久性》一书。

翻译自: https://www.javacodegeeks.com/2015/10/a-beginners-guide-to-read-and-write-skew-phenomena.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值