我们有一个集群Java应用程序运行在mysql 5.5数据库(InnoDb引擎)上。该应用程序使用事务隔离级别设置为SERIALIZABLE的Spring。

在一个方法中(可以在一个节点的不同线程中或在单独的节点中同时执行),内部有一个典型的SELECT-then-UPDATE模式。这是伪代码:

old_status = null;
do {
    old_status = SELECT status
                 FROM bookings
                 WHERE code=123;

    affected_rows = UPDATE bookings
                    SET status=<new_status>
                    WHERE code=123 AND status=<old_status>;

} while (affected_rows == 0);

// Now we can do stuff with <old_status> value


字段code是PK; <old_status><new_status>值始终不同。

SELECTUPDATE在单独的事务上运行。

效果很好。我什至认为AND status=<old_status>语句的WHERE子句中的UPDATE检查是不必要的,因为事务隔离级别为SERIALIZABLE,这意味着先发出SELECT然后发出,而不检查UPDATE字段的值。

因此,第一个问题是:(1)我可以在事务隔离级别为status时不需要所有这些吗?

现在,发生的事情是,几天前,DBA在我的工作场所突然实现,并带有“证明”我们应该开始使用SERIALIZABLE事务隔离级别的参数和度量。由于他几乎从未离开过地下墓穴,所以我立即知道他是认真的。他说,如果我们将事务隔离级别从READ_COMMITED更改为SERIALIZABLE,则cpu的使用率将下降10%,并且查询运行的速度会大大加快,等等。总之,他有他的论据要求我们切换到事务隔离级别。

因此,第二个问题是:(2)鉴于我们已经通过READ_COMMITED检查READ_COMMITED句子的READ_COMMITED子句中status字段的值,我们可以愉快地切换到WHERE事务隔离级别吗? >?

我认为可以,但想先向社区咨询。提前致谢!

注意:我不能使用本机结构,例如mysql的SELECT ... FOR UPDATE等。

最佳答案

如果两者都在单独的事务中,则需要比较旧值。您所做的是在乐观应用程序事务中使用的一种简单技术,称为比较和设置。是的,您可以自由地这样做。

关于读取提交隔离级别,这是事务中唯一有趣的事情。如果您只有一个选择或更新,那么如果我正确地理解了Oracle的实现,则根本不应该有任何不同。 Oracle只访问一次表中的一行,并将重用已经获得的信息。但是他们可能是无法重用这些信息的情况(会话高速缓存用尽等)。

因此,这将需要高水平的理解,并且在不考虑与某些变更的影响有关的每笔交易的情况下,我的意思是所有潜在的变更。因此,如果您希望正确执行此操作,则可以看到成本飞涨。

我永远不会轻易更改隔离级别,尤其是如果您没有为此设计的话。

10-06 09:03