我们有一个集群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>
值始终不同。SELECT
和UPDATE
在单独的事务上运行。效果很好。我什至认为
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只访问一次表中的一行,并将重用已经获得的信息。但是他们可能是无法重用这些信息的情况(会话高速缓存用尽等)。
因此,这将需要高水平的理解,并且在不考虑与某些变更的影响有关的每笔交易的情况下,我的意思是所有潜在的变更。因此,如果您希望正确执行此操作,则可以看到成本飞涨。
我永远不会轻易更改隔离级别,尤其是如果您没有为此设计的话。