在实际开发过程中,如果选择了springboot+jpa的方式,那么和数据库的交互方式就被框架层'过度'封装,别误会,这里的过度封装没有贬义,只是个人水平有限,在翻阅hibernate以及jpa相关源码时,有点一头雾水,折腾蛮久,就是没定位到sql最终在数据库中执行的形式,大多数场景下,yml配置中配置

jpa:
show-sql: true
或者
logging:
level:
org:
hibernate:
type.descriptor.sql.BasicBinder: trace
SQL: debug

这两种形式可以在控制台中输出预执行sql和参数,通过自己替换占位参数也能拼出来sql。大多数场景也就可以满足日常调试需求。

记一次我遇到的场景。
循环执行一条查询sql,发现第二批sql始终返回为空,观察控制台打印的sql,将sql拼上去拿到数据库中执行发现可以查到数据,但是代码层面始终返回为空。

处理成的sql如下:
SELECT ss.* FROM sim_signal_schedules ss WHERE ss.data_source = 2  AND ss.last_updated_date >= 'Mon Oct 25 11:03:26 CST 2021'
and ss.schedule_id in ( 'b77b8df3-3272-4da3-9ff6-34fedc3ac823','bdf45c6e-47ed-44aa-b385-d5f04fe6cab0','d34878f9-fa12-4d17-bea1-45a37fc9eaa7');
时间 Mon Oct 25 11:03:26 CST 2021是完全copy控制台输出的入参,in()里面的参数也是,数据库中通过这条sql确实有数据。

尝试解决的思路有:
  1. 怀疑参数中存在特殊字符导致编码导致的(其实我这里不存在中文和一些特殊字符,关键问题是我for循环调用,前面已经有执行成功的iteration)
  2. 怀疑jpa中sql书写的方式导致(虽然不想排查这个,因为还是存在成功的查询,没法解释)
  3. sql最终的执行形态
最后发现有效的解决方案是3,通过修改配置,输出了jdbc最终的执行sql,发现是jpa中输出参数的binder对时间类型的数据类型的表达和数据库的表达不一致,
数据库中最终的执行sql为:SELECT ss.* FROM sim_signal_schedules ss WHERE ss.data_source = 2  AND ss.last_updated_date >= '10/25/2021 11:03:26.632'
    and ss.schedule_id in ( 'b77b8df3-3272-4da3-9ff6-34fedc3ac823','bdf45c6e-47ed-44aa-b385-d5f04fe6cab0','d34878f9-fa12-4d17-bea1-45a37fc9eaa7');
问题出现了,数据库中date类型中的数据精确到了毫秒,但是binder输出的时候只是精确到秒,坑爹的是我当前的场景下数据还真就精确到了毫秒,这个不同框架下对于date类型的表达,让我找了半天。。。

控制台输出jdbc的配置如下:
pml中引入依赖:
<dependency>
<groupId>com.googlecode.log4jdbc</groupId>
<artifactId>log4jdbc</artifactId>
<version>1.2</version>
</dependency>
yml文件配置:
datasource: ##打印最终执行sql配置
isPrimary: 1
platform: postgres
url: jdbc:log4jdbc:postgresql://10.127.0.11:5432/ftc_simulation?stringtype=unspecified&useAffectedRows=true //注意这里在jdbc和postgresql中添加了log4j
username: sim_dev
password: sim_dev
driver-class-name: net.sf.log4jdbc.DriverSpy //driver-class-name有修改
type: com.zaxxer.hikari.HikariDataSource