think-orm icon indicating copy to clipboard operation
think-orm copied to clipboard

分页功能--buildSql生成的SQL语句不准确导致mysql存在隐式转换的字段查询失效

Open kingfer30 opened this issue 4 years ago • 5 comments

我们mysql中有个status字段类型是enum,即字符串对象,在查询的时候如果传入int类型会触发mysql的隐私转换。(解决办法在TP各种入口将status字段值强制转换为string即可)

但是我们在使用TP6的时候发现使用框架不做强制转换竟然也能查询出来,但是打印出来的SQL语句直接去执行是查不到的: image image

带着好奇心看了think-orm的底层代码发现实际上打印出来的SQL并非真正执行的SQL,真正执行的是通过PDO的prepare以及bindValue,而bindValue中会指定字段对应类型, 这个类型TP6在逻辑里面就会去获取mysql对应表的字段(仅限单表) image image

所以我们判断 TP的打印SQL日志方法【getLastsql()】是有问题的 原本以为不需要在所有入口做强制转换,TP底层就帮我们做了, 但我们发现列表做了分页后, 列表的数据和分页中的total统计结果不一致。

由于通过PDO的bindValue占坑的形式TP6是获取不到mysql最终执行的语句的,我们通过打开mysql打印log, 在真正打印出来的SQL发现 COUNT和select的语句中, COUNT查询竟然没有做转换 image

通过追溯源码, 发现了问题点: TP的分页count和select调用方式不同,而恰好count方法是使用buildSql生成SQL语句再去做查询,而我们上面说到getLastSql这个方法有问题, 查找代码发现buildSql()方法底层最终和getLastsql方法一样是调用了PDOConnection中的getRealSql()方法。这个方法是有问题的,生成出来的语句中隐式转换没有做对 image

image

当然按前面说的,我们通过入口传入的参数全部转为字符串可以解决,但是既然TP底层提供了这个自动转换功能,也希望能把count方法也改一下,不然列表查询是做了转换,但是count又没做转换,导致列表和count查找结果不一致。

kingfer30 avatar Jan 20 '21 10:01 kingfer30

生成的sql仅供参考 你是说你的status在模型里面做了类型转换后无效么?

liu21st avatar Jan 21 '21 01:01 liu21st

生成的sql仅供参考 你是说你的status在模型里面做了类型转换后无效么?

不是啊,,是分页里面调用count方法, count方法恰好调用了buildSql方法的方式去生成sql再去执行获取结果,而分页里面的select又是用bind的方式去获取结果,这样会造成列表数量和count的结果不一致

我知道生成的sql仅供参考,但是你们count方法也用了这个生成的方法, 所以还是有点问题的.

kingfer30 avatar Jan 21 '21 02:01 kingfer30

为啥不能自己规范下传入的数据呢

liu21st avatar Jan 21 '21 03:01 liu21st

为啥不能自己规范下传入的数据呢

我们已经做了规范了哈,我只是提一下你们的分页这个功能,列表(select)和统计(count)的结果调用的方法不同,可能会导致结果不一致~

kingfer30 avatar Jan 21 '21 03:01 kingfer30

改进了下

liu21st avatar Jan 21 '21 08:01 liu21st