最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MySQL邏輯刪除與唯一索引沖突解決方案

 更新時間:2025年07月16日 14:27:00   作者:yifanghub  
本文探討MySQL邏輯刪除與唯一索引沖突問題,提出四種解決方案:復(fù)合索引+時間戳、修改唯一字段、歷史表、業(yè)務(wù)層校驗(yàn),推薦方案1和方案3,適用于不同場景,感興趣的朋友一起看看吧

問題背景

在MySQL數(shù)據(jù)庫設(shè)計(jì)中,邏輯刪除(軟刪除)是一種常見的實(shí)踐,它通過設(shè)置標(biāo)志位(如is_delete)來標(biāo)記記錄被"刪除",而不是實(shí)際刪除數(shù)據(jù)。然而,當(dāng)表中存在唯一約束時,如在用戶表中我們要求用戶名必須唯一,并且用戶數(shù)據(jù)不要物理刪除,那這個時候可能會產(chǎn)生一個問題:

  • 用戶A(username=“Tom”)被邏輯刪除(is_delete=1)
  • 新用戶嘗試使用username="Tom"注冊時
  • 唯一約束阻止創(chuàng)建新記錄,即使原始用戶已被"刪除"

本文將介紹解決此問題的方案。

問題復(fù)現(xiàn)

1.創(chuàng)建用戶表

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY ,
    username VARCHAR(50) NOT NULL COMMENT '用戶名',
    email VARCHAR(100) NOT NULL COMMENT '用戶郵箱',
    is_delete TINYINT(1) NOT NULL DEFAULT 0 COMMENT '邏輯刪除標(biāo)記,用于標(biāo)記當(dāng)前記錄是否已刪除,0:否,1:是'
);

2.執(zhí)行腳本:

-- 插入一條測試數(shù)據(jù),用戶名為:tom
INSERT INTO users (username, email) VALUES ('tom', 'tom@example.com');
-- 邏輯刪除tom用戶(is_delet設(shè)置為1)
UPDATE users SET is_delete = 1 WHERE username = 'tom';
-- 創(chuàng)建同名用戶(is_delete不同)
INSERT INTO users (username, email) VALUES ('tom', 'new_tom@example.com');

在執(zhí)行第三步時,會報錯如下:

[23000][1062] Duplicate entry 'tom' for key 'users.idx_uq_username'

原因分析:從結(jié)果可以看到,在插入相同名字的記錄時,違反了唯一約束idx_uq_username,但實(shí)際上用戶tom已經(jīng)刪除了,唯一索引阻止了用戶名=tom的記錄插入。

解決方案

解決方案1.復(fù)合唯一索引 + 時間戳刪除字段

改動點(diǎn):
1)添加一個字段delete_time,用于記錄被刪除的時間,默認(rèn)值為NULL,當(dāng)刪除該記錄時將該字段設(shè)置為當(dāng)前時間
2)新建復(fù)合唯一索引,將用戶名username和刪除時間delete_time字段包含在復(fù)合唯一索引中

-- 方案1
CREATE TABLE users_test1 (
    id INT AUTO_INCREMENT PRIMARY KEY ,
    username VARCHAR(50) NOT NULL COMMENT '用戶名',
    email VARCHAR(100) NOT NULL COMMENT '用戶郵箱',
    is_delete TINYINT(1) NOT NULL DEFAULT 0 COMMENT '邏輯刪除標(biāo)記,用于標(biāo)記當(dāng)前記錄是否已刪除,0:否,1:是',
    delete_time DATETIME NULL DEFAULT NULL COMMENT '邏輯刪除時間,默認(rèn)為NULL'
);
-- 添加復(fù)合唯一索引
ALTER TABLE users_test1
ADD UNIQUE INDEX idx_unique_username_dt (username, delete_time);
-- 插入初始用戶
INSERT INTO users_test1 (username, email) VALUES ('tom', 'tom@example.com');
-- 邏輯刪除用戶(設(shè)置刪除時間)
UPDATE users_test1 SET is_delete = 1,delete_time = NOW() WHERE username = 'tom';
-- 創(chuàng)建同名新用戶(delete_time為NULL)
INSERT INTO users_test1 (username, email) VALUES ('tom', 'new_tom@example.com');

執(zhí)行完上面腳本發(fā)現(xiàn)并沒有報錯,執(zhí)行查詢sql

select * from users_test1;

結(jié)果如下:

+--+--------+-------------------+---------+-------------------+
|id|username|email              |is_delete|delete_time        |
+--+--------+-------------------+---------+-------------------+
|1 |tom     |tom@example.com    |1        |2025-07-13 14:55:59|
|2 |tom     |new_tom@example.com|0        |null               |
+--+--------+-------------------+---------+-------------------+

解決方案2:刪除后修改唯一字段值

改動點(diǎn):
在邏輯刪除時,為唯一字段添加特定前綴/后綴,使其不再與原有值沖突

-- 方案2 刪除后修改唯一字段值
CREATE TABLE users_test2 (
    id INT AUTO_INCREMENT PRIMARY KEY ,
    username VARCHAR(50) NOT NULL COMMENT '用戶名',
    email VARCHAR(100) NOT NULL COMMENT '用戶郵箱',
    is_delete INT(1) NULL DEFAULT 0 COMMENT '邏輯刪除標(biāo)記,用于標(biāo)記當(dāng)前記錄是否已刪除,0:否,1:是'
);
-- 添加復(fù)合唯一索引
ALTER TABLE users_test2
ADD UNIQUE INDEX idx_unique_username (username);
-- 插入初始用戶
INSERT INTO users_test2 (username, email) VALUES ('tom', 'tom@example.com');
-- 邏輯刪除用戶,修改用戶名
UPDATE users_test2 SET is_delete = 1,username = CONCAT(username, '_deleted_', UUID_SHORT()) WHERE username = 'tom';
-- 創(chuàng)建同名新用戶
INSERT INTO users_test2 (username, email) VALUES ('tom', 'new_tom@example.com');
select * from users_test2;

查詢結(jié)果示例:

+--+------------------------------+-------------------+---------+
|id|username                      |email              |is_delete|
+--+------------------------------+-------------------+---------+
|1 |tom_deleted_100950808475992064|tom@example.com    |1        |
|2 |tom                           |new_tom@example.com|0        |
+--+------------------------------+-------------------+---------+

解決方案3. 使用歷史表

修改點(diǎn):將刪除的記錄移動到專門的歷史表,主表只保留有效記錄

-- 方案3
-- 主表(活躍用戶)
CREATE TABLE users_test3 (
    id INT AUTO_INCREMENT PRIMARY KEY ,
    username VARCHAR(50) NOT NULL COMMENT '用戶名',
    email VARCHAR(100) NOT NULL COMMENT '用戶郵箱',
    is_delete INT(1) NULL DEFAULT 0 COMMENT '邏輯刪除標(biāo)記,用于標(biāo)記當(dāng)前記錄是否已刪除,0:否,1:是'
);
-- 添加復(fù)合唯一索引
ALTER TABLE users_test3
ADD UNIQUE INDEX idx_unique_username (username);
-- 歷史表(已刪除用戶)
CREATE TABLE users_test3_deleted (
    id INT AUTO_INCREMENT PRIMARY KEY ,
    username VARCHAR(50) NOT NULL COMMENT '用戶名',
    email VARCHAR(100) NOT NULL COMMENT '用戶郵箱',
    is_delete INT(1) NULL DEFAULT 0 COMMENT '邏輯刪除標(biāo)記,用于標(biāo)記當(dāng)前記錄是否已刪除,0:否,1:是'
);
-- 添加歷史表復(fù)合唯一索引
ALTER TABLE users_test3_deleted 
ADD UNIQUE INDEX idx_unique_username (username);
-- 插入測試數(shù)據(jù)
INSERT INTO users_test3 (username, email) VALUES ('tom', 'tom@example.com');
-- 邏輯刪除:移動到歷史表
INSERT INTO users_test3_deleted (id, username, email,is_delete)
SELECT id, username, email,1 FROM users_test3 WHERE username = 'tom';
-- 刪除原紀(jì)錄
DELETE FROM users_test3 WHERE username = 'tom';
-- 可以重新創(chuàng)建原用戶名
INSERT INTO users_test3 (username, email) VALUES ('tom', 'new_tom@example.com');
select * from users_test3;
select * from users_test3_deleted;

解決方案4. 業(yè)務(wù)層校驗(yàn)+更新記錄

修改點(diǎn):
保持唯一索引不變,在業(yè)務(wù)層處理沖突

-- 創(chuàng)建表(普通唯一索引)
CREATE TABLE users_test4 (
    id INT AUTO_INCREMENT PRIMARY KEY ,
    username VARCHAR(50) NOT NULL COMMENT '用戶名',
    email VARCHAR(100) NOT NULL COMMENT '用戶郵箱',
    is_delete INT(1) NULL DEFAULT 0 COMMENT '邏輯刪除標(biāo)記,用于標(biāo)記當(dāng)前記錄是否已刪除,0:否,1:是'
);
-- 業(yè)務(wù)層邏輯示例偽代碼:
/*
1. 先查詢是否存在已刪除的同名用戶
   SELECT id FROM users_test4 WHERE username = ? AND is_delete = 1
2. 如果存在,則更新原記錄(恢復(fù))
   UPDATE users_test4 SET is_delete = 0, email = ? WHERE username = ?
3. 如果不存在,則新建記錄
   INSERT INTO users_test4 (username, email) VALUES (?, ?)
*/

總結(jié)

  • 復(fù)合唯一索引 + 時間戳刪除字段:需要需修改表結(jié)構(gòu),適用于新項(xiàng)目設(shè)計(jì),需保留完整數(shù)據(jù)歷史且查詢頻繁的系統(tǒng);
  • 刪除后修改唯一字段值:需要修改業(yè)務(wù)字段(如用戶名),可能影響日志或歷史記錄追溯,適用于臨時解決方案;
  • 使用歷史表:需同步維護(hù)兩個表結(jié)構(gòu),備份恢復(fù)方便,查詢主表的數(shù)據(jù)量比較小,查詢效率高,適用于數(shù)據(jù)量大、刪除頻繁且需要嚴(yán)格區(qū)分活躍/歷史數(shù)據(jù)的系統(tǒng);
  • 業(yè)務(wù)層校驗(yàn)+更新記錄:不用修改字段,需編寫額外校驗(yàn)和恢復(fù)邏輯,可能存在并發(fā)問題風(fēng)險;

綜合以上,建議采用方案1和方案3

到此這篇關(guān)于MySQL邏輯刪除與唯一索引沖突解決的文章就介紹到這了,更多相關(guān)mysql邏輯刪除與唯一索引沖突內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Mac os 解決無法使用localhost連接mysql問題

    Mac os 解決無法使用localhost連接mysql問題

    今天在mac上搭建好了php的環(huán)境,把先前在window、linux下運(yùn)行良好的程序放在mac上,居然出現(xiàn)訪問不了數(shù)據(jù)庫,數(shù)據(jù)庫連接的host用的是localhost,可以確認(rèn)數(shù)據(jù)庫配置是正確的,下面特為大家分享下
    2014-05-05
  • Mysql之EXPLAIN顯示using filesort介紹

    Mysql之EXPLAIN顯示using filesort介紹

    EXPLAIN 是mysql解釋select查詢的一個關(guān)鍵字,可以很方便的用于調(diào)試
    2012-02-02
  • MySQL索引之聚集索引介紹

    MySQL索引之聚集索引介紹

    在MySQL中,InnoDB引擎表是(聚集)索引組織表(clustered index organize table),而MyISAM引擎表則是堆組織表(heap organize table)
    2015-12-12
  • Mysql案例刨析事務(wù)隔離級別

    Mysql案例刨析事務(wù)隔離級別

    隔離性其實(shí)比想象要復(fù)雜。在SQL中定義了四種隔離的級別,每一種隔離級別都規(guī)定了一個事務(wù)中的修改,哪些是在事務(wù)內(nèi)和事務(wù)間是可見的,哪些是不可見的。較低級別的隔離通常來說能承受更高的并發(fā),系統(tǒng)的開銷也會更小
    2021-09-09
  • MACOS中忘記MySQL root密碼的解決方案

    MACOS中忘記MySQL root密碼的解決方案

    這篇文章主要向大家講述的是在MAC系統(tǒng)中MySQL重設(shè)root密碼的實(shí)際操作步驟,在實(shí)際操作中忘記MySQL root密碼時常會發(fā)生的,下面就是本教程的詳細(xì)內(nèi)容介紹。
    2017-03-03
  • MySQL5.7.31 64位免安裝版使用教程圖解

    MySQL5.7.31 64位免安裝版使用教程圖解

    這篇文章主要介紹了MySQL5.7.31 64位免安裝版使用教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-10-10
  • 解決MySQL啟動常見錯誤:ERROR 2002(HY000) Can‘t connect to local MySQL server through socket‘tmp問題

    解決MySQL啟動常見錯誤:ERROR 2002(HY000) Can‘t connect

    這篇文章主要介紹了解決MySQL啟動常見錯誤:ERROR 2002(HY000) Can‘t connect to local MySQL server through socket‘tmp問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • MLSQL Stack如何讓流調(diào)試更加簡單詳解

    MLSQL Stack如何讓流調(diào)試更加簡單詳解

    這篇文章主要給大家介紹了關(guān)于MLSQL Stack如何讓流調(diào)試更加簡單的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用MLSQL具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • 關(guān)于SQL的cast()函數(shù)解析

    關(guān)于SQL的cast()函數(shù)解析

    這篇文章主要介紹了關(guān)于SQL的cast()函數(shù)解析,CAST函數(shù)用于將某種數(shù)據(jù)類型的表達(dá)式顯式轉(zhuǎn)換為另一種數(shù)據(jù)類型。CAST()函數(shù)的參數(shù)是一個表達(dá)式,它包括用AS關(guān)鍵字分隔的源值和目標(biāo)數(shù)據(jù)類型,需要的朋友可以參考下
    2023-04-04
  • mysql存儲過程原理與用法詳解

    mysql存儲過程原理與用法詳解

    這篇文章主要介紹了mysql存儲過程,結(jié)合圖文與實(shí)例形式較為詳細(xì)的分析了mysql存儲過程基本概念、原理、用法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下
    2020-04-04

最新評論

炎陵县| 墨江| 祁门县| 武胜县| 东山县| 庐江县| 肃宁县| 永川市| 两当县| 达尔| 四平市| 新乡县| 永平县| 淮南市| 兴海县| 高邑县| 民和| 沛县| 繁昌县| 赤城县| 莎车县| 祁连县| 恭城| 游戏| 会泽县| 澄江县| 成都市| 喜德县| 招远市| 方山县| 自治县| 纳雍县| 呼伦贝尔市| 日土县| 江达县| 花莲县| 万安县| 壶关县| 南雄市| 松潘县| 天祝|