insert on duplicate key update命令
這里寫目錄標(biāo)題
- 背景介紹
- 實現(xiàn)方式
- 先判斷再操作
- insert on duplicate
- 擴(kuò)展
- 返回值
- 分庫分表返回主鍵
- 執(zhí)行步驟
- death lock
背景介紹
有一批消息隊列任務(wù)要執(zhí)行,需要記錄任務(wù)相關(guān)的數(shù)據(jù),包括執(zhí)行總數(shù)、成功數(shù)、失敗數(shù)。這里采用mysql統(tǒng)計表的方式記錄,每一批任務(wù)生成一條統(tǒng)計數(shù)據(jù),但由于消息隊列是無序的,所以生成統(tǒng)計記錄的時候無法知道哪一個請求是第一次,也就不知道是 insert 還是 update。
簡單列一下統(tǒng)計表字段
CREATE TABLE `t_statistics` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵',`task_id` bigint(20) unsigned NOT NULL COMMENT '任務(wù)ID',`total_count` bigint(20) unsigned DEFAULT '0' COMMENT '總數(shù)',`success_count` bigint(20) unsigned DEFAULT '0' COMMENT '成功數(shù)',`fail_count` bigint(20) unsigned DEFAULT '0' COMMENT '失敗數(shù)',PRIMARY KEY (`id`),UNIQUE KEY `uk_task_id` (`task_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='任務(wù)統(tǒng)計表'注意:
- primary key: id 自增主鍵
- unique key: task_id 任務(wù)ID
實現(xiàn)方式
先判斷再操作
既然不知道哪次請求是第一次,那就先判斷任務(wù)記錄是否存在,不存在則insert,存在則update
if ( (select * from t_statistics where task_id = %d) != null ) {update t_statistics set total_count = total_count + 1, ... ; } else {insert into t_statistics values(xxx...); }存在的問題:
1.每一次處理都需有兩次數(shù)據(jù)庫操作,暫用數(shù)據(jù)庫連接且增加了RT
2.操作非原子性,會有并發(fā)問題
- 兩次不同任務(wù)的請求發(fā)現(xiàn)DB里沒有數(shù)據(jù),決定都執(zhí)行insert操作,第一個請求成功insert,第二個請求發(fā)送唯一鍵沖突將拋出 duplicate entry 異常
- 兩次不同任務(wù)的請求發(fā)現(xiàn)DB里有數(shù)據(jù),決定都執(zhí)行update操作,假設(shè)這時候DB里的total_count=1,第一次請求 +1后 total_count=2,第二次請求 +1 后 total_count=2,按理說數(shù)據(jù)庫最后 total_count應(yīng)該為3,但是由于數(shù)據(jù)發(fā)生了臟寫最后為2
insert on duplicate
這種場景下可以使用 insert on duplicate 命令,簡單的說下該命令的原理:執(zhí)行 insert 命令時發(fā)生主鍵沖突或者唯一鍵沖突,就執(zhí)行后面的 update 命令,如果沒發(fā)生沖突就執(zhí)行 insert 命令。
insert into t_statistics values(xxx...) on duplicate key update total_count = total_count + 1, ... ;可以看到命令更為簡潔,操作也保持了原子性不會發(fā)生并發(fā)問題。
擴(kuò)展
返回值
使用 insertOnDuplicate 的返回值是什么?
<insert id="insertOnDuplicate" parameterType="xxx.StatisticsDO"> insert into t_statistics values(xxx...) on duplicate key update total_count = total_count + 1, ... ; </insert>- insert -> 1
- update -> 2
- nothing -> 0
分庫分表返回主鍵
嘗試過多種方法后發(fā)現(xiàn)不能返回歷史數(shù)據(jù)的主鍵,所以可以通過返回值來判斷是否是insert還是update,再判斷怎么獲取主鍵,偽代碼如下:
return pk; } else {return selectId(xxx); }執(zhí)行步驟
1.嘗試把新行插入到表中
2.當(dāng)因為對于主鍵或唯一關(guān)鍵字出現(xiàn)重復(fù)關(guān)鍵字錯誤而造成插入失敗時,則對現(xiàn)有的行加上S(共享)鎖,然后返回該行數(shù)據(jù)給server層
3.server在內(nèi)存對該行執(zhí)行update操作
4.對該行記錄加上X(排他)鎖
5.將update后的結(jié)果寫入該行
death lock
總結(jié)
以上是生活随笔為你收集整理的insert on duplicate key update命令的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微信、qq可以上网,但是浏览器却不能上网
- 下一篇: 什么是cmd?常见的cmd命令 cd、m