mybatis批量插入,批量更新以及null值問題的解決
前言
mybatis批量插入、批量更新常規(guī)寫法,及升級寫法
null value in column “xxx” violates not-null constraint mybatis批量操作報錯問題處理。
批量插入
常規(guī)寫法:
<insert id="insertUser" parameterType="com.test.UserEntity">
insert into t_com_user(user_name, age, gender)
values
<foreach collection ="list" item="item" index="index" open="(" close= ")" separator= "),(">
#{item.userName, jdbcType=VARCHAR},
#{item.age, jdbcType=INTEGER},
#{item.gender, jdbcType=INTEGER}
</foreach>
</insert>
假如我們在批量插入數(shù)據(jù)的時候,還想做一下關(guān)聯(lián)查詢,該怎么辦?
如下寫法,免去了先查詢數(shù)據(jù),然后遍歷list賦值,再批量插入的操作
<insert id="insertUser" parameterType="com.test.UserEntity">
insert into t_com_user(user_name, age, gender, dept_name)
select
t1.user_name, t1.age, t1.gender, t2.dept_name
from (
VALUES
<foreach collection ="list" item="item" index="index" open="(" close= ")" separator= "),(">
#{item.userName, jdbcType=VARCHAR},
#{item.age, jdbcType=INTEGER},
#{item.gender, jdbcType=INTEGER},
#{item.deptId, jdbcType=INTEGER}
</foreach>
) as t1 (user_name, age, gender, dept_id)
left_join t_com_dept t2 on t1.dept_id = t2.id
</insert>
批量更新
常規(guī)寫法
這種寫法實際執(zhí)行過程是單條執(zhí)行,即使使用的是id查找數(shù)據(jù),但是效率較差。
<update id="updateUser" parameterType="com.test.UserEntity">
<foreach collection ="list" item="item" index="index" separator= ";">
update t_com_user set
user_name = #{item.userName, jdbcType=VARCHAR},
age = #{item.age, jdbcType=INTEGER},
gender = #{item.gender, jdbcType=INTEGER}
where id = #{item.id, jdbcType=INTEGER}
</foreach>
</update>
升級寫法:參考批量插入操作,使用連表更新的語法
<update id="updateUser" parameterType="com.test.UserEntity">
update t_com_user t1 set
user_name = t2.user_name,
age = t2.age,
gender = t2.gender
from (
values
<foreach collection ="list" item="item" index="index" open="(" close= ")" separator= "),(">
#{item.id, jdbcType=INTEGER},
#{item.userName, jdbcType=VARCHAR},
#{item.age, jdbcType=INTEGER},
#{item.gender, jdbcType=INTEGER}
</foreach>
) as t2 (id, user_name, age, gender)
where t1.id = t2.id
</update>
ERROR: null value in column “user_name” violates not-null constraint mybatis 批量操作報錯問題處理
mybatis的批量操作過程,傳入的list對象集合中,對象的某個屬性難免會為null,如果數(shù)據(jù)庫表該列恰好有not-null限制,則會報錯;
處理辦法,本文以pgsql的批量更新為例,親測可行:
方法一:使用
COALESCE(#{item.userName, jdbcType=VARCHAR}, ‘默認名稱')方式二:
user_name = COALESCE(t2.user_name, ‘默認名稱')
二選一即可
<update id="updateUser" parameterType="com.test.UserEntity">
update t_com_user t1 set
user_name = COALESCE(t2.user_name, '默認名稱'),
age = t2.age,
gender = t2.gender
from (
values
<foreach collection ="list" item="item" index="index" open="(" close= ")" separator= "),(">
#{item.id, jdbcType=INTEGER},
COALESCE(#{item.userName, jdbcType=VARCHAR}, '默認名稱'),
#{item.age, jdbcType=INTEGER},
#{item.gender, jdbcType=INTEGER}
</foreach>
) as t2 (id, user_name, age, gender)
where t1.id = t2.id
</update>
mysql 使用IFNULL函數(shù) pgsql 使用COALESCE函數(shù)
方法二:
在foreach中使用if標簽判斷
<if test= "item.userName != null">
#{item.userName, jdbcType=VARCHAR}
</if>
<if test= "item.userName == null">
'默認名稱'
</if>
Oracle mysql下,不支持 from (value (),()) as t 的寫法;可以參考
select * from ( select 1, '張三' from dual union select 2, '李四' from dual ) t
null 原因
當mybatis做批量插入時,插入的字段可能沒值,此時不做處理的話,mybatis會報異常,執(zhí)行失敗
根據(jù)mybatis的官網(wǎng)介紹,此時需要添加對應(yīng)的jdbcType類型映射,以處理null值 ,具體的映射關(guān)系參考:jdbc映射關(guān)系表
此時,在所有可能為空的字段取值中添加jdbcType=XXX(一般全部添加即可)
案例
1.使用union all 來串連每個values,其中jdbcType的設(shè)置可以使null值也輸入進去
<insert id="saveList" parameterType="java.util.List">
INSERT INTO DDZHPT.CMS_SCHEDUAL_DETIAL
(
DEPT_ID,
SCHEDUAL_DATE,
CMS_SCHEDUAL_TYPE_ID,
CMS_SCHEDUAL_TEAM_ID,
CMS_SCHEDUAL_TYPE_PERIOD_ID,
CMS_SCHEDUAL_TIME_ID,
SYS_POST_ID,
POINT_ID,
PERSON_ID
)
<foreach collection="list" item="item" index="index" separator="union all">
SELECT
#{item.deptId,jdbcType=DECIMAL},
#{item.schedualDate,jdbcType=TIMESTAMP},
#{item.cmsSchedualTypeId,jdbcType=VARCHAR},
#{item.cmsSchedualTeamId,jdbcType=VARCHAR},
#{item.cmsSchedualTypePeriodId,jdbcType=VARCHAR},
#{item.cmsSchedualTimeId,jdbcType=VARCHAR},
#{item.sysPostId,jdbcType=VARCHAR},
#{item.pointId,jdbcType=VARCHAR},
#{item.personId,jdbcType=VARCHAR}
FROM DUAL
</foreach>
</insert>
2.純粹使用foreach
<insert id="saveList" parameterType="java.util.List">
<foreach collection="list" item="item" index="index" separator="union all">
INSERT INTO DDZHPT.CMS_SCHEDUAL_DETIAL
(
DEPT_ID,
SCHEDUAL_DATE,
CMS_SCHEDUAL_TYPE_ID,
CMS_SCHEDUAL_TEAM_ID,
CMS_SCHEDUAL_TYPE_PERIOD_ID,
CMS_SCHEDUAL_TIME_ID,
SYS_POST_ID,
POINT_ID,
PERSON_ID
)VALUES(
#{item.deptId,jdbcType=DECIMAL},
#{item.schedualDate,jdbcType=TIMESTAMP},
#{item.cmsSchedualTypeId,jdbcType=VARCHAR},
#{item.cmsSchedualTeamId,jdbcType=VARCHAR},
#{item.cmsSchedualTypePeriodId,jdbcType=VARCHAR},
#{item.cmsSchedualTimeId,jdbcType=VARCHAR},
#{item.sysPostId,jdbcType=VARCHAR},
#{item.pointId,jdbcType=VARCHAR},
#{item.personId,jdbcType=VARCHAR}
)
</foreach>
</insert>
推薦使用第一種方式,數(shù)據(jù)庫語句只有一條,減少數(shù)據(jù)庫執(zhí)行語句的負擔
3.union與union all區(qū)別

<!--插入所有列清單-->
<sql id="insertAllCol">
<trim prefix="(" suffix=")" suffixOverrides=",">
FPH,
EFFECTIVE_TAX_AMOUNT,
PURCHASER_TAXNO,
INVOICE_STATE,
DEDUCTIBLE_MODE,
AMOUNT,
OVERDUE_CHECK_MARK,
ABNORMAL_TYPE,
NSRSBH,
ANTI_FAKE_CODE,
UPDATE_TIME,
DEDUCTIBLE_PERIOD,
AGENCY_DRAWBACK,
RESALE_CERTIFICATE_NUMBER,
INVOICE_NO,
CREATE_TIME,
INV_ISSUE_DATE,
TAX,
AUDIT_STATE,
DEDUCTIBLE_TYPE,
DEDUCTIBLE_DATE,
MANAGEMENT_STATUS,
SALES_TAXNAME,
DEDUCTIBLE_STATE,
FLOW_ID,
INVOICE_CATAGORY,
SALES_TAXNO,
INVOICE_CODE,
ORIGINAL_PERIOD,
INFO_SOURCES,
</trim>
</sql>
<sql id="insertAllValueWithItem" databaseId="oracle">
<trim prefix=" SELECT " suffix=" FROM dual " suffixOverrides=",">
#{item.fph,jdbcType=VARCHAR},
#{item.effectiveTaxAmount,jdbcType=NUMERIC},
#{item.purchaserTaxno,jdbcType=VARCHAR},
#{item.invoiceState,jdbcType=DATE},
#{item.deductibleMode,jdbcType=VARCHAR},
#{item.amount,jdbcType=NUMERIC},
#{item.overdueCheckMark,jdbcType=VARCHAR},
#{item.abnormalType,jdbcType=VARCHAR},
#{item.nsrsbh,jdbcType=VARCHAR},
#{item.antiFakeCode,jdbcType=VARCHAR},
#{item.updateTime,jdbcType=DATE},
#{item.deductiblePeriod,jdbcType=VARCHAR},
#{item.agencyDrawback,jdbcType=VARCHAR},
#{item.resaleCertificateNumber,jdbcType=VARCHAR},
#{item.invoiceNo,jdbcType=VARCHAR},
#{item.createTime,jdbcType=DATE},
#{item.invIssueDate,jdbcType=VARCHAR},
#{item.tax,jdbcType=NUMERIC},
#{item.auditState,jdbcType=NUMERIC},
#{item.deductibleType,jdbcType=VARCHAR},
#{item.deductibleDate,jdbcType=VARCHAR},
#{item.managementStatus,jdbcType=VARCHAR},
#{item.salesTaxname,jdbcType=VARCHAR},
#{item.deductibleState,jdbcType=VARCHAR},
#{item.flowId,jdbcType=NUMERIC},
#{item.invoiceCatagory,jdbcType=VARCHAR},
#{item.salesTaxno,jdbcType=VARCHAR},
#{item.invoiceCode,jdbcType=VARCHAR},
#{item.originalPeriod,jdbcType=VARCHAR},
#{item.infoSources,jdbcType=VARCHAR},
</trim>
</sql>
注:union all和union的區(qū)別
union all連接查詢,結(jié)果不去重
union做連接查詢結(jié)果去重
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot配置文件bootstrap和application區(qū)別及說明
這篇文章主要介紹了SpringBoot配置文件bootstrap和application區(qū)別及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-06-06
Java使用雙異步實現(xiàn)將Excel的數(shù)據(jù)導(dǎo)入數(shù)據(jù)庫
在開發(fā)中,我們經(jīng)常會遇到這樣的需求,將Excel的數(shù)據(jù)導(dǎo)入數(shù)據(jù)庫中,這篇文章主要來和大家講講Java如何使用雙異步實現(xiàn)將Excel的數(shù)據(jù)導(dǎo)入數(shù)據(jù)庫,感興趣的可以了解下2024-01-01
Java讀取properties配置文件時,出現(xiàn)中文亂碼的解決方法
下面小編就為大家?guī)硪黄狫ava讀取properties配置文件時,出現(xiàn)中文亂碼的解決方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-11-11
Java開發(fā)中的23種設(shè)計模式詳解(推薦)
本篇文章主要介紹了Java開發(fā)中的23種設(shè)計模式詳解,現(xiàn)在分享給大家,也給大家做個參考。感興趣的小伙伴們可以參考一下。 設(shè)計模式(Design Patterns)2016-11-11
使用Java編寫一個簡單的Web的監(jiān)控系統(tǒng)
這篇文章主要介紹了使用Java編寫一個簡單的Web的監(jiān)控系統(tǒng)的例子,并且將重要信息轉(zhuǎn)為XML通過網(wǎng)頁前端顯示,非常之實用,需要的朋友可以參考下2015-11-11

