Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reuse PreparedStatement cause cache of route result do not clean #372

Closed
laowhites opened this issue Sep 12, 2017 · 6 comments
Closed

Reuse PreparedStatement cause cache of route result do not clean #372

laowhites opened this issue Sep 12, 2017 · 6 comments

Comments

@laowhites
Copy link

laowhites commented Sep 12, 2017

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

@terrymanu
Copy link
Member

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

@laowhites
Copy link
Author

laowhites commented Sep 12, 2017

升级1.5.3 问题依然存在

@terrymanu
Copy link
Member

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

@KomachiSion
Copy link
Member

当使用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。

@KomachiSion
Copy link
Member

KomachiSion commented Jul 25, 2018

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

terrymanu added a commit that referenced this issue Jul 25, 2018
for #372, clear routedStatements in ShardingPreparedStatement before …
@terrymanu terrymanu changed the title 一个事物中多次分表查询,当路由到同一张表是则查询正常,路由不同的表则异常 Reuse PreparedStatement cause cache of route result do not clean Aug 8, 2018
@terrymanu
Copy link
Member

fixed at 3.0.0.M2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants