問題場景
這個是公司專案進行更改,將專案的資料庫從Oracle版本改為PostgreSQL版本時發生的錯誤。
控制檯報錯內容。
SQL: insert into table (...,RQ,...) select ...,?,... union all select ...,?,...
//(這裡的...省略了其他欄位, 主要是RQ日期型別報錯就沒列出)
Cause: org.postgresql.util.PSQLException: 錯誤: 欄位 "rq" 的型別為 timestamp without time zone, 但表示式的型別為 text
建議:你需要重寫或轉換表示式 位置:404
mapper檔案中的動態sql為
<insert id="insert" parameterType="java.util.List">
insert into table
(
-- 省略,
RQ,
-- 省略)
<foreach collection="list" item="item" separator="union all">
select
-- 省略,
#{item.rq,jdbcType=TIMESTAMP},
-- 省略
-- from dual 這裡當時是將專案Oracle資料庫轉為PostgreSQL資料庫
</foreach>
</insert>
對應的實體類為
@Data
public class Entity {
// 省略
private Date rq;
// 省略
}
當在插入資料到資料庫的時候就會報欄位RQ型別錯誤的問題,但是透過檢查sql語句後並沒有發現明顯的錯誤。
雖然控制檯報錯了,但還是能插入幾條資料到資料庫中,然後就報錯不能插入了。這個時候考慮到有可能插入資料的問題,但是這裡設定了#{item.rq,jdbcType=TIMESTAMP}
,資料型別也是符合PostgreSQL資料庫的日期型別timestamp的,所以也不是這個的問題。
這個時候我將資料庫中的資料清除,重新執行了幾遍程式後發現有時候能夠向資料庫中插入幾條資料,然後就報錯,有時候一條資料都沒有插入就報錯了,很是奇怪。
解決方法
後面使用了PostgreSQL的特定的語法,在rq後面加上::timestamp
就能夠正常插入了,如下
<insert id="insert" parameterType="java.util.List">
insert into table
(
-- 省略,
RQ,
-- 省略)
<foreach collection="list" item="item" separator="union all">
select
-- 省略,
#{item.rq,jdbcType=TIMESTAMP}::timestamp,
-- 省略
-- from dual -- 這裡是Oracle資料庫的語法
</foreach>
</insert>
但這樣每個日期的欄位都要加上這個,更改起來很麻煩,所以我在想有沒有更好的解決方案。
後面我更改了這一條批次插入的動態sql。由於這個sql在Oracle資料庫中是能夠正常的執行的,有可能在PostgreSQL資料庫存在相容的問題,所以改成了在使用Mysql資料庫時常寫的動態sql,如下:
<insert id="inser" parameterType="java.util.List">
insert into table (
-- 省略,
RQ,
-- 省略)
values
<foreach collection="list" item="item" separator=",">
(
-- 省略,
#{item.rq,jdbcType=TIMESTAMP},
-- 省略
)
</foreach>
</insert>
重新執行程式後,沒有報錯,資料正常插入,完美解決!