mybatis批量插入,批量更新以及null值问题的解决
作者:凌兮~
前言
mybatis批量插入、批量更新常规写法,及升级写法
null value in column “xxx” violates not-null constraint mybatis批量操作报错问题处理。
批量插入
常规写法:
<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>
假如我们在批量插入数据的时候,还想做一下关联查询,该怎么办?
如下写法,免去了先查询数据,然后遍历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>
批量更新
常规写法
这种写法实际执行过程是单条执行,即使使用的是id查找数据,但是效率较差。
<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,如果数据库表该列恰好有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函数 pgsql 使用COALESCE函数
方法二:
在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会报异常,执行失败
根据mybatis的官网介绍,此时需要添加对应的jdbcType类型映射,以处理null值 ,具体的映射关系参考:jdbc映射关系表
此时,在所有可能为空的字段取值中添加jdbcType=XXX(一般全部添加即可)
案例
1.使用union all 来串连每个values,其中jdbcType的设置可以使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>
推荐使用第一种方式,数据库语句只有一条,减少数据库执行语句的负担
3.union与union all区别
<!--插入所有列清单--> <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的区别
union all连接查询,结果不去重
union做连接查询结果去重
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。