mybatis执行自定义sql时,多出一个limit

报错信息:

### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'LIMIT 10' at line 19
; bad SQL grammar []; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'LIMIT 10' at line 19

执行自定义sql,在方法中没有使用任何分页插件,但是项目中其它地方有引用PageHelper,单独调试这个方法没有发现问题,在测试过程中发现偶现的sql错误问题,参考http://www.herohuang.com/2018/08/08/pagehelper-limit/ 成功解决问题。

原因:

PageHelper 方法使用了静态的 ThreadLocal 参数,分页参数和线程是绑定的。

只要你可以保证在 PageHelper 方法调用后紧跟 MyBatis 查询方法,这就是安全的。因为 PageHelper 在 finally 代码段中自动清除了 ThreadLocal 存储的对象。

线程中start的page 不能保证线程在当前执行退出时清理完page变量

复现:

在执行PageHelper.start(pageNum,pageSize);方法后,参数page变量,如xx!=null,直接返回XX,则page没有被消费,这个参数就会一直保留在这个线程上。当这个线程再次被使用时,如果接下来执行其它sql,就可能导致不该分页的方法去消费这个分页参数,这就产生了莫名其妙的分页。

如果PageHelper.start(pageNum,pageSize);之后的方法加了缓存,也会有这个问题。

解决方法:

1.使用参数方式是极其安全的
2.保证在 PageHelper 方法调用后紧跟 MyBatis 查询方法,必须保证分页和查询同时有效。
3.调PageHelper.clearPage();

什么是ThreadLocal?

MybatisPlus 和 PageHelper插件都通过使用threadLocal 来实现分页功能,那么什么是threadLocal呢?

使用方法

        ThreadLocal threadLocal = new ThreadLocal<>();
        threadLocal.remove();//清空
        threadLocal.get();//获取
        threadLocal.set(new Object());//赋值
 
  

官方解释:

/**
 * This class provides thread-local variables.  These variables differ from
 * their normal counterparts in that each thread that accesses one (via its
 * {@code get} or {@code set} method) has its own, independently initialized
 * copy of the variable.  {@code ThreadLocal} instances are typically private
 * static fields in classes that wish to associate state with a thread (e.g.,
 * a user ID or Transaction ID).
 */

ThreadLocal是一个线程内部的数据存储类,通过它可以在当前线程存储数据,其内部维护了一个ThreadLocalMap,其内部Entity继承WeakReference,key是当前threadLocal对象。

使用场景:

当某些数据是以线程为作用域并且不同线程具有不同的数据副本的时候

你可能感兴趣的:(mp)