1. 程式人生 > >MySQL -- INSERT ON DUPLICATE KEY UPDATE 使用

MySQL -- INSERT ON DUPLICATE KEY UPDATE 使用

前言:

 MySQL 中 INSERT ON DUPLICATE KEY UPDATE 這個方法可能不是很常用,但卻很好用,它主要功能是:當插入的資料中的主鍵 與 資料庫中現有的資料主鍵 重複的情況下就不會執行插入操作,而是可以對現有的資料進行更新操作,不存在相同主鍵則執行插入操作。

下面來說說,我為什麼會需要這樣的操作:

假設有表 A,B,C,他們的主鍵分別是 a-pk,b-pk,c-pk

A表結構
a-pk b-pk c-pk other
md5(bbcc) bb cc 66
md5(2233) 22 33 55
  • 其中A表是報表資料表,它是由 b-pk,c-pk 來確定唯一一條資料,最開始的想法是,通過建立(b-pk,c-pk)的聯合唯一約束 來確保資料行的唯一性,若插入失敗,說明已經存在相同的 b-pk,c-pk 組合,則對 other 欄位進行更新操作。是否可以進行優化一下?不建立聯合唯一約束可以不?
  • 因為 b-pk,c-pk,他們本身作為主鍵具有唯一性,由此他們的組合也應當具有唯一性,通過簡單的 b-pk+c-pk 字串拼接可得出一個唯一的字串,可作為 A 表的主鍵 a-pk 的值,這樣可以確保唯一性,也可以免掉 MySQL 獲取自增主鍵所帶來的消耗。
  • 同時為了使A表主鍵長度在一定範圍內,所以我們再對 b-pk+c-pk 拼接的字串結果進行 32位 MD5 後作為 A 表的主鍵,MD5 是十六進位制,所以32位的 MD5 個數有 16的32次方個,這個數非常大,40億的4次方個數,除非你的表資料超過了 40億的4次方行,不然不可能會重複的。
  • 主鍵是通過 md5(b-pk+c-pk) 外部生成的,所以可以直接利用主鍵唯一性約束來確保資料行唯一性,這樣就不需要建立(b-pk,c-pk)聯合唯一約束。到這裡夠好了嗎?這樣還是需要先插入,失敗則更新,需要兩條SQL,有沒有可以更好的?
  • 當然還可以更好,我想了想我這種操作正好適用 插入主鍵重複時做更新操作,於是就用了文章開頭所說的方法 INSERT ON DUPLICATE KEY UPDATE

使用:

1.單條資料插入(以表A為例)

固定更新引數值:

INSERT INTO A (a-pk,b-pk,c-pk,other) VALUES (md5(bbcc),bb,cc,666) ON DUPLICATE KEY UPDATE other=666;

傳入更新引數值:

INSERT INTO A (a-pk,b-pk,c-pk,other) VALUES (md5(bbcc),bb,cc,666) ON DUPLICATE KEY UPDATE other=VALUES(other);

上面兩條SQL執行後 other 值都為 666,當沒有相同資料執行插入時返回的受影響行數為 1,當相同的時候執行更新操作返回的受影響行數為 2(一條是我們準備插入的,一條是原有更新的)。

2.批量資料插入

單欄位更新:

INSERT INTO `student_course`(`id`, `user_id`, `nc_id`, `nc_user_id`, `nc_commodity_id`, `course_no`, `course_name`, `business_id`) 
VALUES 
(277941, 11056941, '1001EE1000000043G2T5', '1001EE1000000043G2TO', '1001A5100000003YABO2', 'kckm303', '工業會計實戰V9.0--55', 'kuaiji'),
(277942, 11056941, '1001EE1000000043G2T5', '1001EE1000000043G2TO', '1001A5100000003YABO2', 'kckm303', '工業會計實戰V9.0--66', 'kuaiji'),
(277943, 11056941, '1001EE1000000043G2T5', '1001EE1000000043G2TO', '1001A5100000003YABO2', 'kckm303', '工業會計實戰V9.0--77', 'kuaiji')
ON DUPLICATE KEY UPDATE
    course_name = VALUES(course_name);

多欄位更新:

INSERT INTO `student_course`(`id`, `user_id`, `nc_id`, `nc_user_id`, `nc_commodity_id`, `course_no`, `course_name`, `business_id`) 
VALUES 
(277941, 11056941, '1001EE1000000043G2T5', '1001EE1000000043G2TO', '1001A5100000003YABO2', 'kckm303', '工業會計實戰V9.0--55', 'kuaiji'),
(277942, 11056941, '1001EE1000000043G2T5', '1001EE1000000043G2TO', '1001A5100000003YABO2', 'kckm303', '工業會計實戰V9.0--66', 'kuaiji')
ON DUPLICATE KEY UPDATE
    course_name = VALUES(course_name),
    business_id = VALUES(business_id);

3.Mybatis中的使用

<insert id="insertBatch" parameterType="java.util.List" >
		INSERT INTO bi_log_student_attend (
		id, user_plan_id, class_type_id,
		compliance_per, creation_time, modified_time
		)
		VALUES
		<foreach collection="list" index="index" item="item" separator="," >
		(
			#{item.id,jdbcType=VARCHAR},
			#{item.userPlanId,jdbcType=BIGINT},
			#{item.classTypeId,jdbcType=BIGINT},
			#{item.compliancePer,jdbcType=DECIMAL},
			#{item.creationTime,jdbcType=TIMESTAMP},
			#{item.modifiedTime,jdbcType=TIMESTAMP}
		)
		</foreach>
		ON DUPLICATE KEY UPDATE
		compliance_per = VALUES(compliance_per),
		modified_time = VALUES(modified_time)
	</insert>

關注公眾號,分享乾貨,討論技術