jianliu opened a new issue #11583:
URL: https://github.com/apache/shardingsphere/issues/11583


   ## Bug Report
   
   I found a concurrency issues when exeucte transaction statement sqls.
   here is my sql statemtns(MySQL)
   ```
   set autocommit=false
   select  * from tablexx where sharding_key=?
   update  tablexx set x=x where sharding_key=?
   commit
   ```
   the client create 200 connections to the proxy and concurrently execute this 
transaction statements to get the TPS data
   
   As above,here is 4 statements
   the first is a begin statement and the LocalTransactionManager will add 
connectionPostProcessors to invoke the real connection`s setAutoCommit(false) 
once a real connection is borrow from datasource in future
   the last statement commit will invoke the real connection`s commit method to 
submit the transaction
   
   ps:
   statement is execute in the thread pool: 
UserExecutorGroup.getInstance().getExecutorService(),it is a shard pool for all 
commandExecutorTask
   
   ### Which version of ShardingSphere did you use?
   5.0.0-RC1-SNAPSHOT
   ### Which project did you use? ShardingSphere-JDBC or ShardingSphere-Proxy?
   ShardingSphere-Proxy
   ### Expected behavior
   Every transaction statement commit success and affect to the MySQL
   ### Actual behavior
   It is hard to find the error,according to my tests,only 0.015% probability 
to get the error below:
   Can't call commit when autocommit=true
   ### Reason analyze (If you can)
   As I analyzed , the reason has two parts
   1.BackendConnection`s field connectionPostProcessors is not thread safe
   
![image](https://user-images.githubusercontent.com/1589099/127616581-43c79abe-907d-4c93-8388-124361cdc017.png)
   although this is not the main reason,but it`s a potential issue
   the 4 statement will execute serially along a connection.
   let's imagine the 4 statement is execute in multiple threads 
   ```
   set autocommit=false     -- sql1:thread1
   select  * from tablexx where sharding_key=?  -- sql2:thread2
   update  tablexx set x=x where sharding_key=?  -- sql3:thread3
   commit -- sql4:thread4
   ```
   set autocommit=false will let the BackendConnection`s 
localTransactionManager add a connectionPostProcessors  to invoke the real 
connection`s setAutoCommit(false) once a real connection is borrow from 
datasource
   when sql2 execute in thread 2, a real connection will be get and apply the 
connectionPostProcessors,but may not see the latest 
   connectionPostProcessors ,cause the real connection never execute 
setAutoCommit(false)
   
   2.CommandExecutorTask`s method run has sequence problem
   
   I think this sequence problem cause concurrency issues on a single 
connection,and it's dangerous
   
![image](https://user-images.githubusercontent.com/1589099/127618468-a18cef0d-02f9-41b4-be59-88ab861c1c45.png)
   code1 will lead the client get response immediately,and client know this 
transaction is finished and could reuse the connection to run the next 
statement.
   code2 clear the resources under the backendConncection like clean 
cachedConnections and connectionPostProcessors (etc.)when transaction is 
finished
   
   so what happened ? because code1 flush the response in thread4,the client  
send next statement "set autocommit=false" for another transaction,and thread6 
execute it and add a connectionPostProcessors,then thread4 run the code2,clear 
the resources include thread6 just created
   
   ```
   set autocommit=false     -- sql1:thread1
   select  * from tablexx where sharding_key=?  -- sql2:thread2
   update  tablexx set x=x where sharding_key=?  -- sql3:thread3
   commit -- sql4:thread4
   
   #next sql statement 
   set autocommit=false     -- sql1:thread6
   select  * from tablexx where sharding_key=?  -- sql2:thread7
   ...
   ```
   It is a sequence problem,but make the object backendConnection be modified 
concurrently.
   
   
   ### Steps to reproduce the behavior, such as: SQL to execute, sharding rule 
configuration, when exception occur etc.
   This is a problem that can be analyzed and concluded and hard to reproduce 
unless rewrite the code ,and a sleep between code1 and code2
   ### Example codes for reproduce this issue (such as a github link).
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


Reply via email to