在實際開發過程中,如果選擇了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
