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

 更新时间:2024年01月13日 10:31:11   作者:凌兮~  
这篇文章主要介绍了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做连接查询结果去重

总结

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

相关文章

  • SpringBoot配置文件bootstrap和application区别及说明

    SpringBoot配置文件bootstrap和application区别及说明

    这篇文章主要介绍了SpringBoot配置文件bootstrap和application区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-06-06
  • java默认方法sqrt实例用法

    java默认方法sqrt实例用法

    在本篇文章里小编给大家分享的是一篇关于java默认方法sqrt实例用法,对此有兴趣的朋友们可以跟着学习下。
    2021-03-03
  • Java中的base64编码器

    Java中的base64编码器

    这篇文章介绍了Java中的base64编码器,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-04-04
  • Java使用双异步实现将Excel的数据导入数据库

    Java使用双异步实现将Excel的数据导入数据库

    在开发中,我们经常会遇到这样的需求,将Excel的数据导入数据库中,这篇文章主要来和大家讲讲Java如何使用双异步实现将Excel的数据导入数据库,感兴趣的可以了解下
    2024-01-01
  • SpringBoot中的main方法注入service

    SpringBoot中的main方法注入service

    这篇文章主要介绍了SpringBoot中的main方法注入service操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06
  • Java读取properties配置文件时,出现中文乱码的解决方法

    Java读取properties配置文件时,出现中文乱码的解决方法

    下面小编就为大家带来一篇Java读取properties配置文件时,出现中文乱码的解决方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-11-11
  • Java 中实现异步的多种方式

    Java 中实现异步的多种方式

    文章介绍了Java中实现异步处理的几种常见方式,每种方式都有其特点和适用场景,通过选择合适的异步处理方式,可以提高程序的性能和可维护性,感兴趣的朋友一起看看吧
    2025-03-03
  • Java开发中的23种设计模式详解(推荐)

    Java开发中的23种设计模式详解(推荐)

    本篇文章主要介绍了Java开发中的23种设计模式详解,现在分享给大家,也给大家做个参考。感兴趣的小伙伴们可以参考一下。 设计模式(Design Patterns)
    2016-11-11
  • 使用Java编写一个简单的Web的监控系统

    使用Java编写一个简单的Web的监控系统

    这篇文章主要介绍了使用Java编写一个简单的Web的监控系统的例子,并且将重要信息转为XML通过网页前端显示,非常之实用,需要的朋友可以参考下
    2015-11-11
  • 如何将应用的log4j替换成logback详解

    如何将应用的log4j替换成logback详解

    无论从设计上还是实现上,Logback相对log4j而言有了相对多的改进。所以下面这篇文章主要给大家介绍了关于如何将应用的log4j换成logback的相关资料,文中介绍的很详细,需要的朋友可以参考下。
    2017-02-02

最新评论