java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > mybatis批量插入,批量更新以及null值问题

mybatis批量插入,批量更新以及null值问题的解决

作者:凌兮~

这篇文章主要介绍了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做连接查询结果去重

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文