近日降雨頗多,偶然迸發靈感,對於防止重複插入這個問題想到了另外一種解決方案(方案三)。sql
電商項目中,一個商品能夠綁定多個標籤,一個標籤能夠綁定多個商品,因此確定會存在一箇中間表對商品和標籤的關聯,假設關聯表goods_label
結構以下:bash
字段 | 類型 | 註釋 |
---|---|---|
id | bigint | 主鍵 |
goods_id | bigint | 商品id |
label_id | bigint | 標籤id |
is_delete | tinyint | 邏輯刪除標識,1爲已刪除,2爲未刪除 |
A和B同時對商品作標籤綁定的操做:分佈式
A -> 綁定商品1和標籤1
B -> 綁定商品1和標籤1
複製代碼
那麼咱們的指望是A和B的操做只會成功其一,另外一個提醒他操做失敗。ui
接下來將會有幾種方案來達到咱們想要的預期~spa
僞代碼:code
var goods_id = 1
var label_id = 1
var id = getId()
var count = select count(0) from goods_label where goods_id = $goods_id and label_id = $label_id and is_delete = 2
if count > 0{
return "已存在關聯"
}
var l = lock.try(GOODS_LABEL_LOCK_KEY + goods_id)
if l != nil{
try{
var row = insert into goods_label(id, goods_id, label_id, is_delete) values ($id, $goods_id, $label_id, 2)
if row > 0{
return "成功"
}
return "失敗"
} finally{
l.release()
}
}else{
return "操做超時"
}
複製代碼
這種很經常使用,也很普通...沒有一絲靈魂索引
將goods_id
和label_id
以及is_delete
設爲聯合惟一索引,那麼僞代碼能夠這樣寫:事務
var goods_id = 1
var label_id = 1
var id = getId()
var count = select count(0) from goods_label where goods_id = $goods_id and label_id = $label_id and is_delete = 2
if count > 0{
return "已存在關聯"
}
var row = insert into goods_label(id, goods_id, label_id, is_delete) values ($id, $goods_id, $label_id, 2)
if row > 0{
return "成功"
}
return "失敗"
複製代碼
代碼簡潔了很多,可是表的索引結構會複雜致使tps
降低,is_delete
字段也被限制了同一條記錄只會存在1和2兩個結果。資源
var goods_id = 1
var label_id = 1
var id = getId()
var count = select count(0) from goods_label where goods_id = $goods_id and label_id = $label_id and is_delete = 2
if count > 0{
return "已存在關聯"
}
var trans = beginTrans()
// 1
var row = insert into goods_label(id, goods_id, label_id, is_delete) values ($id, $goods_id, $label_id, 1)
if row > 0{
// 2
row = update goods_label set is_delete = 2 where id = $id and (select t.count from (select count(0) as count from goods_label where goods_id = $goods_id and label_id = $label_id and is_delete = 2) t) = 0
if row > 0{
trans.commit()
return "成功"
}
trans.rollback()
return "失敗"
}
return "失敗"
複製代碼
這種方案會執行兩條操做事務sql:get
能夠發現,若是tag 2執行失敗,整個事務會回滾掉,那麼tag 1的操做也會撤銷,因此也不會產生髒數據。