专栏首页Java冰冻三尺PageHelper导致自定义Mybatis拦截器不生效

PageHelper导致自定义Mybatis拦截器不生效

> 公众号:[Java小咖秀](https://t.1yb.co/jwkk),网站:[javaxks.com](https://www.javaxks.com)

> 作者: water_lang ,来源:www.jianshu.com/p/8dc9f8a4cce9

一、前言

某一天,开发问我,为什么针对一个查询会有两条记录,且其中一条记录并不符合条件select * from tablea where xxno = 170325171202362928;``xxno170325171202362928170325171202362930的都出现在结果中。

一个等值查询为什么会有另外一个不同值的记录查询出来呢?

我们一起来看看究竟!

二、分析

我们查看该表结构,发现xxnovarchar 类型,但是等号右边是一个数值类型,这种情况下 MySQL 会如何进行处理呢?

官方文档如下:https://dev.mysql.com/doc/refman/5.6/en/type-conversion.html

The following rules describe how conversion occurs for comparison operations: .... 省略一万字 .... In all other cases, the arguments are compared as floating-point (real) numbers.

也就是说,他会将等于号的两边转换成浮点数来做比较。

Comparisons that use floating-point numbers (or values that are converted to floating-point numbers) are approximate because such numbers are inexact. This might lead to results that appear inconsistent:

如果比较使用了浮点型,那么比较会是近似的,将导致结果看起来不一致,也就是可能导致查询结果错误。

我们测试下刚刚生产的例子:

mysql > select '170325171202362928' = 170325171202362930;
+-------------------------------------------+
| '170325171202362928' = 170325171202362930 |
+-------------------------------------------+
|                                         1 |
+-------------------------------------------+
1 row in set (0.00 sec)

可以发现,字符串的'170325171202362928' 和 数值的170325171202362930比较竟然是相等的。

我们再看下字符串'170325171202362928' 和字符串'170325171202362930' 转化为浮点型的结果:

mysql  > select '170325171202362928'+0.0;
+--------------------------+
| '170325171202362928'+0.0 |
+--------------------------+
|    1.7032517120236294e17 |
+--------------------------+
1 row in set (0.00 sec)
​
mysql > select '170325171202362930'+0.0;
+--------------------------+
| '170325171202362930'+0.0 |
+--------------------------+
|    1.7032517120236294e17 |
+--------------------------+
1 row in set (0.00 sec)

我们发现,将两个不同的字符串转化为浮点数后,结果是一样的。

所以只要是转化为浮点数之后的值是相等的,那么,经过隐式转化后的比较也会相等,我们继续进行测试其他转化为浮点型相等的字符串的结果。

mysql > select '170325171202362931'+0.0;
+--------------------------+
| '170325171202362931'+0.0 |
+--------------------------+
|    1.7032517120236294e17 |
+--------------------------+
1 row in set (0.00 sec)
​
mysql > select '170325171202362941'+0.0;
+--------------------------+
| '170325171202362941'+0.0 |
+--------------------------+
|    1.7032517120236294e17 |
+--------------------------+
1 row in set (0.00 sec)

字符串'170325171202362931''170325171202362941'转化为浮点型结果一样,我们看下他们和数值的比较结果。

mysql > select '170325171202362931' = 170325171202362930;
+-------------------------------------------+
| '170325171202362931' = 170325171202362930 |
+-------------------------------------------+
|                                         1 |
+-------------------------------------------+
1 row in set (0.00 sec)
​
mysql > select '170325171202362941' = 170325171202362930;
+-------------------------------------------+
| '170325171202362941' = 170325171202362930 |
+-------------------------------------------+
|                                         1 |
+-------------------------------------------+
1 row in set (0.00 sec)

结果也是符合预期的。

因此,当 MySQL 遇到字段类型不匹配的时候,会进行各种隐式转化,一定要小心,有可能导致精度丢失。

For comparisons of a string column with a number, MySQL cannot use an index on the column to look up the value quickly. If str_col is an indexed string column, the index cannot be used when performing the lookup in the following statement:

如果字段是字符型,且上面有索引的话,如果查询条件是用数值来过滤的,那么该 SQL 将无法利用字段上的索引

SELECT * FROM tbl_name WHERE str_col=1;

The reason for this is that there are many different strings that may convert to the value 1, such as '1', '1', or '1a'.

我们进行测试:

mysql > create table tbl_name(id int ,str_col varchar(10),c3 varchar(5),primary key(id),key idx_str(str_col));
Query OK, 0 rows affected (0.02 sec)
​
mysql  > insert into tbl_name(id,str_col) values(1,'a'),(2,'b');
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0
​
mysql  > insert into tbl_name(id,str_col) values(3,'3c'),(4,'4d');
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0
​
mysql  > desc select * from tbl_name where str_col='a';
+----+-------------+----------+------+---------------+---------+---------+-------+------+--------------------------+
| id | select_type | table    | type | possible_keys | key     | key_len | ref   | rows | Extra                    |
+----+-------------+----------+------+---------------+---------+---------+-------+------+--------------------------+
|  1 | SIMPLE      | tbl_name | ref  | idx_str       | idx_str | 13      | const |    1 | Using where; Using index |
+----+-------------+----------+------+---------------+---------+---------+-------+------+--------------------------+
​
mysql  > desc select * from tbl_name where str_col=3;
+----+-------------+----------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table    | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+----------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | tbl_name | ALL  | idx_str       | NULL | NULL    | NULL |    4 | Using where |
+----+-------------+----------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
​
mysql [localhost] {msandbox} (test) > select * from tbl_name where str_col=3;
+----+---------+------+
| id | str_col | c1   |
+----+---------+------+
|  3 | 3c      | NULL |
+----+---------+------+
1 row in set, 2 warnings (0.00 sec)

同时我们可以看到,我们用数值型的3str_col进行比较的时候,他无法利用索引,同时取出来的值也是错误的:

mysql  > show warnings;
+---------+------+----------------------------------------+
| Level   | Code | Message                                |
+---------+------+----------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: '3c' |
| Warning | 1292 | Truncated incorrect DOUBLE value: '4d' |
+---------+------+----------------------------------------+

MySQL 针对3c4d这两个值进行了转化,变成了34

三、小结

在数据库中进行查询的时候,不管是 Oracle 还是 MySQL,一定要注意字段类型,杜绝隐式转化,不仅会导致查询缓慢,还会导致结果错误。

作者:Harvey 来源:https://urlify.cn/MJjMZv

原文链接:http://www.jianshu.com/p/8dc9f8a4cce9

我来说两句

0 条评论
登录 后参与评论

相关文章

  • PageHelper导致自定义Mybatis拦截器不生效

    最近由于公司要做统一的数据变更记录,以前是基于Aop来做的,这样效率很低,而且在做批量处理(insert,update,delete)操作时基本不可用。所以我打...

    Java小咖秀
  • 彻底搞懂MyBatis插件原理及PageHelper原理

    提到插件,相信大家都知道,插件的存在主要是用来改变或者增强原有的功能,MyBatis中也一样。

    公众号 IT老哥
  • 掌握MyBatis插件原理轻松写出自己的PageHelper分页插件

    提到插件,相信大家都知道,插件的存在主要是用来改变或者增强原有的功能,MyBatis中也一样。

    程序员追风
  • MyBatis之分页插件(PageHelper)工作原理

      数据分页功能是我们软件系统中必备的功能,在持久层使用mybatis的情况下,pageHelper来实现后台分页则是我们常用的一个选择,所以本文专门类介绍下。

    用户4919348
  • 用了这么多年分页PageHelper,才发现自己一直用错了!

    在实际项目运用中,PageHelper的使用非常便利快捷,仅通过PageInfo + PageHelper两个类,就足以完成分页功能,然而往往这种最简单的集成使...

    业余草
  • Spring Boot:实现MyBatis分页

    想必大家都有过这样的体验,在使用Mybatis时,最头痛的就是写分页了,需要先写一个查询count的select语句,然后再写一个真正分页查询的语句,当查询条件...

    朝雨忆轻尘
  • MyBatis插件原理分析,看完感觉自己better了

    在Mybatis中最出名的就是PageHelper 分页插件,下面我们先来使用一下这个分页插件。

    田维常
  • Mybatis自定义SQL拦截器

    本博客介绍的是继承Mybatis提供的Interface接口,自定义拦截器,然后将项目中的sql拦截一下,打印到控制台。

    SmileNicky
  • 30.MyBatis插件原理与Spring集成

    myBatis启动时扫描<plugins>标签,注册到Configuration对象的InterceptorChain中。通过setProperties将参数放...

    编程之心
  • PageHelper的前世今生

    记得之前在参加面试的时候,有个面试官给我提了一个问题:请说一下PageHelper分页插件的底层原理。当听到这个问题的时候既熟悉又陌生,熟悉是因为平时都在使用它...

    阿Q说代码
  • Mybatis拦截器之数据加密解密

    Mybatis Interceptor 在 Mybatis 中被当作 Plugin(插件),不知道为什么,但确实是在 org.apache.ibatis.plu...

    用户4172423
  • CRUD 程序猿的 Mybatis 进阶

    通过对 product 表进行 CRUD 操作,来梳理 Mybatis 动态标签 <if>、<where>、<foreach>、<trim>、<set>、<ch...

    SupremeSir
  • Spring boot Mybatis-XML方式分页查询PageHelper(五)

    楠楠
  • 原 spring boot 整合mybat

    kinbug [进阶者]
  • SpringBoot整合MVC Mybatis plus 最全thymeleaf讲解(保姆级讲解,带Java代码案例讲解)

    默认的静态资源路径为: classpath:/META-INF/resources/ 或者 classpath:/resources/ ...

    CaesarChang张旭
  • PageHelper分页插件怎么这么好用

    参数说明https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToU...

    码农飞哥
  • MyBatis常见好用的插件

    在没有分页插件之前,写一个分页需要两条SQL语句,一条查询一条统计,然后才能计算出页码,这样的代码冗余而又枯燥,更重要的一点是数据库迁移,众所周知不同的数据库分...

    java乐园
  • Mybatis源码学习(四)拦截器与插件原理

    回顾前几文加载mybatis时,会通过sqlSessionFactoryBuilder的build方法对xml文件进行解析,解析成document树后,...

    虞大大
  • Spring Boot + Spring Cloud 实现权限管理系统 后端篇(八):MyBatis分页功能实现

    使用Mybatis时,最头痛的就是写分页,需要先写一个查询count的select语句,然后再写一个真正分页查询的语句,当查询条件多了之后,会发现真不想花双倍的...

    朝雨忆轻尘

扫码关注云+社区

领取腾讯云代金券