Shardingsphere: Reuse PreparedStatement cause cache of route result do not clean

Created on 12 Sep 2017  ·  6Comments  ·  Source: apache/shardingsphere

Please answer these questions before submitting your issue. Thanks!

Which version of Sharding-Jdbc do you using?

1.5.3

Expected behavior

使用mybaits作为orm框架
开启spring事物支持时,在mybaits的settings中将defaultExecutorType设置为REUSE,
在同一个事物中查询时,即使路由不同的表查询正常

Actual behavior

开启事物
路由到同一张表是则查询正常,路由不同的表则异常

Steps to reproduce the behavior

1.启动项目
2Controller包下的的方法
3.点击控制台打印的路径 http://localhot:8081/select
若想不产生这个bug可以采取如下两种方法之一
1.关闭事物
2.开启事物则需将mybatisConfig.xml的defaultExecutorType设置为SIMPLE

Please provide the reproduce example codes (such as github link) if possible.

https://git.oschina.net/lxhs/com.study.demo.git

bug

All 6 comments

请先试一下1.5.x是否有问题

升级1.5.3 问题依然存在

好的,spring事务问题,我们一直疏于梳理,会在未来梳理

当使用REUSE作为Mybatis的defaultExecutorType时,ReuseExecutor会缓存事务中的PreparedStatement,因此在执行事务中第一个查询语句时,ReuseExecutor缓存了ShardingPreparedStatement,执行第二个语句时复用了该Statement;
在ShardingPreparedStatement中,会有记录已经路由好的实际Statement,并且根据路由好的Statement的数量,来判断是否需要进行ResultSets的merge;

由于Spring事务开启,并且mybatis采用了Reuse方式,所以同事务的2个查询语句在同一个ShardingPreparedStatement中就会有2个对应的routedStatement。
但是第一个查询语句会在查询完毕时关闭ResultSet

因此,在第二个语句执行时,ShardingPreparedStatement检测到了2个RoutedStatement,认为需要启动merge步骤,在mergeEngine中,从RoutedStatement获取到了第一条语句已经关闭并置null的ResultSet,因此导致了空指针异常的bug。

The defaultExecutor will cache the prepared statement for the same sql when defaultExecutorType configures REUSE.Because of the cached statement, the second SQL in transaction will reuse the ShardingPreparedStatement the first SQL used.
ShardingPreparedStatement also cached these routed statements of actual datasources, and would determine whether a merge behavior required base on the size of routedStatements.

So, when the demo use Spring Transaction and set defaultExecutorType as REUSE, the size of routedStatements will be two after executing the second SQL.
But the resultSet of first SQL will be closed by mybatis after handling.

Finally, the results of actual statement cached in routedStatements will be setted null in ResultSetImpl.realClose.So, when ShardingPreparedStatement executes the merge step, the mergeEngine get a NULL and cause a NullPointerException

fixed at 3.0.0.M2

Was this page helpful?
0 / 5 - 0 ratings