ON DUPLICATE KEY存在即更新否则即插入的研究

182 阅读2分钟

 今天有个业务需求,在新增某数据的时候,要求批量操作,批量插入或者覆盖(更新)等,本来是想分步骤,1.查询是否存在 2.根据1的结果选择insert或update语句

或者全部用insert,但是那样就得搭上一个delete语句,但是怎么看都是笨到家了。

项目现在用的SSM,mybatis里有很多方法可以处理这种情况,我选择的方式是ON DUPLICATE KEY UPDATE句式。这种方法可以放在insert标签内。完整语句是这样的:

<insert id="uploadPlanItemCache" >		
	INSERT INTO t_ms_check_plan_item (
		p_id,i_id,vehicle_type,i_type,record,record_remark,big_item,i_position,small_item,
		checkman_name,create_id,create_name,create_time)
	VALUES
	<foreach  collection="list"   item="queryParam" separator="," close=";">	
		(#{queryParam.planId}, #{queryParam.itemId}, #{queryParam.vehicleType},#{queryParam.itemType},
		#{queryParam.record},#{queryParam.recordRemark},#{queryParam.bigItem},#{queryParam.itemPosition},
		#{queryParam.smallItem},#{queryParam.checkMan},#{queryParam.userId},#{queryParam.userName},NOW()) 
		ON DUPLICATE KEY UPDATE record = #{record},recordRemark = #{recordRemark},
		create_id=#{userId},create_name=#{userName},create_time = NOW()	
	</foreach>
</insert>

t_ms_check_plan_item这张表的主键是id,自增的,所以在代码里面没有去insert,自增就可以了,不用给它传值。ON DUPLICATE KEY UPDATE这个句子,后面跟的传参赋值很简单,比如我的代码里,我写了record、recordRemark、create_id、create_name、create_time这几个字段,这几个字段就是当数据库已经存在某条数据,但是你想去更新这条数据中的哪几个字段,那五个字段就是我要update上去的。

要更新某条数据,那肯定要找到这条数据,ON DUPLICATE KEY UPDATE是根据什么来找的呢,很简单,主键咯,因为主键不可重复。

我建了一张表来做测试。

​三个字段,分别是id、a_a、b_b其中,id是主键,不允许为空。

不管是手动还是用语句,id都是显然不可能重复的。

执行一下普通的插入语句:

INSERT INTO t_ms_test (a_a, b_b)VALUES("a", "b")

结果:

执行一下带ON DUPLICATE KEY 的句子:

INSERT INTO t_ms_test (a_a, b_b)VALUES("a", "b") ON DUPLICATE KEY UPDATE b_b = "a"

可以看到,我是想更新了b_b这个字段,结果是:

可以看到,并没有去进行update的操作,因为ON DUPLICATE KEY默认是根据主键的,id身为主键本身是自增的,我的insert语句也没有去操作id,我只是给a_a和b_b这两个字段传值了,所以这种情况下,永远不会触发update,因为id自增,永远不会重复的,那么上述语句将会永远在执行新增。

那么如果我不想新增,我只想更新b_b这个字段,怎么办,那就建立索引。将a_a这个字段固定。

我在给a_a这个字段建立索引的时候,数据库报:​这是因为a_a想成为一个Unique的索引,那么就不能重复,而我在刚才测试的时候,a_a的第一条和第二条都是a。删除之后保存索引。

我截断了表,重新执行

INSERT INTO t_ms_test (a_a, b_b)VALUES("a", "b") ON DUPLICATE KEY UPDATE b_b = "a"

第一次执行结果:​第二次执行结果:

可以看到,id没变,第二次执行的是update操作,根据a_a来update了b_b字段。

执行

INSERT INTO t_ms_test (a_a, b_b)VALUES("b", "b") ON DUPLICATE KEY UPDATE b_b = "c"

结果:​因为a_a的值变了,所以新增数据。

现在回到我最开始的那段应用代码

<insert id="uploadPlanItemCache" >		
	INSERT INTO t_ms_check_plan_item (
		p_id,i_id,vehicle_type,i_type,record,record_remark,big_item,i_position,small_item,
		checkman_name,create_id,create_name,create_time)
	VALUES
	<foreach  collection="list"   item="queryParam" separator="," close=";">	
		(#{queryParam.planId}, #{queryParam.itemId}, #{queryParam.vehicleType},#{queryParam.itemType},
		#{queryParam.record},#{queryParam.recordRemark},#{queryParam.bigItem},#{queryParam.itemPosition},
		#{queryParam.smallItem},#{queryParam.checkMan},#{queryParam.userId},#{queryParam.userName},NOW()) 
		ON DUPLICATE KEY UPDATE record = #{record},recordRemark = #{recordRemark},
		create_id=#{userId},create_name=#{userName},create_time = NOW()	
	</foreach>
</insert>

t_ms_check_plan_item这张表,id自增,如果我直接使用ON DUPLICATE KEY,那么将会去依据id,那么就会跟上述例子一样,id永远不会重复,那就永远在insert。

实际上我的p_id+i_id这两个字段相加,可以确定唯一性,也就是说,我可以根据p_id+i_id来update其他字段,根据上述例子,很简单,用p_id+i_id来建立联合索引。