pagehelper 4.x 多线程 bug

当查询同一sql,在高并发情况下

或出现 (4.1.x)

NullPointerException

或者 

无法处理该类型[class com.github.pagehelper.sqlsource.PageDynamicSqlSource]的SqlSource



分析:
SqlUtils 处
private Page doProcessPage(Invocation invocation, Page page, Object[] args) throws Throwable {
    ...
    //判断并处理为PageSqlSource
if (!isPageSqlSource(ms)) {
processMappedStatement(ms);
}
    try {
...
//简单的通过total的值来判断是否进行count查询
if (page.isCount()) {
page.setCountSignal(Boolean.TRUE);
//替换MS
args[0] = msCountMap.get(ms.getId());
...
} else {
page.setTotal(-1l);
}
...
} finally {
((PageSqlSource)ms.getSqlSource()).removeParser();
}

//返回结果
return page;
}

public void processMappedStatement(MappedStatement ms) throws Throwable {
SqlSource sqlSource = ms.getSqlSource();
MetaObject msObject = SystemMetaObject.forObject(ms);
SqlSource pageSqlSource;
if (sqlSource instanceof StaticSqlSource) {
pageSqlSource = new PageStaticSqlSource((StaticSqlSource) sqlSource);
} else if (sqlSource instanceof RawSqlSource) {
pageSqlSource = new PageRawSqlSource((RawSqlSource) sqlSource);
} else if (sqlSource instanceof ProviderSqlSource) {
pageSqlSource = new PageProviderSqlSource((ProviderSqlSource) sqlSource);
} else if (sqlSource instanceof DynamicSqlSource) {
pageSqlSource = new PageDynamicSqlSource((DynamicSqlSource) sqlSource);
} else {
throw new RuntimeException("无法处理该类型[" + sqlSource.getClass() + "]的SqlSource");
}
msObject.setValue("sqlSource", pageSqlSource);
//由于count查询需要修改返回值,因此这里要创建一个Count查询的MS
msCountMap.put(ms.getId(), MSUtils.newCountMappedStatement(ms));
}
 
1、NullPointerException 分析 

  线程1 进入 processMappedStatement 方法,
  将 pageSqlSource 替换 pageSqlSource = new PageDynamicSqlSource((DynamicSqlSource) sqlSource);
  但未执行 msCountMap.put(ms.getId(), MSUtils.newCountMappedStatement(ms));
  线程2进入 isPageSqlSource 方法,判断为true,进入后面的逻辑
  执行 args[0] = msCountMap.get(ms.getId()) ,此时 获取的值为空,则报异常

2、 无法处理该类型[class com.github.pagehelper.sqlsource.PageDynamicSqlSource]的SqlSource 分析
  线程1刚进入 processMappedStatement 方法,此时 sqlSource 的值还未替换   线程2进入 isPageSqlSource 方法,为
false,进入processMappedStatement 方法,此时线程 1 已经替换sqlSource 则线程2抛出异常
 
原文地址:https://www.cnblogs.com/jaxlove-it/p/13753666.html