seata Read Committed bug in SelectForUpdateExecutor.java

piztneat  于 2023-02-04  发布在  Java
关注(0)|答案(2)|浏览(180)
  • I have searched the issues of this repository and believe that this is not a duplicate.

Ⅰ. Issue Description

Normally, Seata supports the isolation level of Read Uncommited, but it does support Read Committed level by forupdate sql which is dealed in SelectForUpdateExecutor.java.

But in the method 'doExecute' of SelectForUpdateExecutor.java, the code

rs = this.statementCallback.execute(this.statementProxy.getTargetStatement(), args);

is firstly executed, then span checking the global lock. In extremly condition, it will cause Dirty Read in two Global Transactional.

For example (Global Transactional-1 as GT1 and Global Transactional-1 as GT2), a record is already updated in a finished Branch Transactional of GT1, then GT2 query this record before GT1 release global lock, then GT2 rollback because of a RuntimeException, then GT1 break span checking and
return rs; Because the record in GT2 is queried between GT1's update sql and rollback action, it is a instant dirty data;

Time axis like this:
GT1: --update Record A--------------------Rollback--------------------------------------->
GT2:-------------------- query Record A--------------Break span and return Record A----->

Ⅱ. Describe what happened

So, in my test code, i construct a case through adding some codes in GT1:
sleep(10000);
throw RuntimeException
after a finished Branch Transactional which update a record, then running GT2 to query the same record in GT1's sleeping duration. GT2 get a dirty data.

Ⅲ. Describe what you expected to happen

In my point, i think that a global forupade should acquire the global row lock, then executes query sql, then release global lock. Like this, we can avoid a dirty reading.

this solution can resolve this problem.

wish seata global forupdate perform as same as single Transactional in Read Committed Isolation level.

best wish!!

Ⅳ. How to reproduce it (as minimally and precisely as possible)

as example as Ⅱ

Ⅴ. Anything else we need to know?

Ⅵ. Environment:

  • JDK version :1.8
  • OS : mac OS
  • Others:
2nbm6dog

2nbm6dog1#

@quhaiyang Here is a plan to make the for update into the global lock before querying. The goal is to make the for update behavior of distributed transactions conform to the behavior of local transactions.
but in this case, if GTS query Record A with for update it can't return anything Unless the transaction is end.

uubf1zoe

uubf1zoe2#

@slievrly I am very appreciate it that you response it so quickly. The two Isolation Levels of Read Uncommitted and Read Committed are both frequently used in many application scene. Indeed, Read Committed Level takes more performance loss, but it is necessary for many cases. I'll wait in hope that this plan is coming to true.

thank you for your response again, and best wishes~

相关问题