能,但仅在单实例MySQL中可靠;分布式环境下需全局ID服务或唯一映射表保障,因分库后各实例索引互不感知。
唯一索引能拦住并发插入重复数据吗
能,但只在单实例 MySQL 里可靠。只要两个事务同时执行
,且都试图写入同一组
字段值,其中一个会被
或更常见的是
直接拒绝——这是 MySQL 唯一索引最核心的保障机制。
实操建议:
必须把业务上“不能重复”的字段组合(比如
、
)明确定义为
,不能只靠应用层校验
建索引时注意字段顺序和
处理:MySQL 认为
,所以含
的列参与唯一约束时,可能意外绕过检查
不要依赖
判断是否存在——这中间有竞态窗口,高并发下必出问题
分布式环境下唯一索引为什么失效
不是索引失效,是“唯一性”这个语义被拆到了多个 MySQL 实例上。比如分库分表后,
的记录可能落在 db1 和 db2 两个库,各自都有自己的
约束,但彼此不感知对方数据。
常见错误现象:
用
分片后,仍对全局唯一的
建本地唯一索引 → 各分片都能插入相同
误以为
或
能跨库生效 → 它们只作用于当前连接的单个实例
用雪花算法生成 ID,却没把机器 ID 或数据中心 ID 纳入分片路由逻辑 → 不同实例可能生成相同 ID
怎么在分库分表中真正保唯一
得把“唯一性判定”从存储层上移到一个全局可协调的环节。MySQL 自身不提供跨库唯一性保证,必须引入外部机制或重构设计。
MySQL(Linux)
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
下载
实操建议:
全局唯一 ID 必须由中心服务生成(如
、
、自建号段服务),且该服务本身要支持高可用和容错,不能成为单点瓶颈
对业务强依赖唯一性的字段(如手机号、邮箱),单独建一张全局唯一映射表(
),所有写操作先
,成功后再写业务表
避免在分片键之外再搞复杂唯一约束;如果真需要,考虑改用
+ 应用层幂等控制 + 补偿任务兜底,而不是强一致
唯一索引和事务隔离级别的关系
唯一索引的冲突检测发生在
执行时,与事务隔离级别无关;但
阶段的可见性会影响你“以为没重复”的判断。比如在
下,事务 A 插入未提交,事务 B 查不到那条记录,就可能跟着插一次,然后 A 提交,B 就报唯一冲突。
关键点:
也不能避免唯一冲突——它只保证本事务内多次
结果一致,不阻止其他事务插入
唯一约束的检查是加在索引记录上的
,不是行锁也不是表锁,但会阻塞其他事务对相同唯一值的插入尝试
如果业务允许最终一致性,可以接受
错误,并在应用层捕获
后走重试或降级逻辑
真正麻烦的从来不是怎么建索引,而是当你的数据开始跨库、跨机房、跨 AZ 时,“唯一”这件事就不再由数据库自动兜底了。这时候得想清楚:哪一层该承担这个责任?能不能接受短暂不一致?有没有足够快的补偿通道?
INSERTUNIQUEDeadlock found when trying to get lockDuplicate entry 'xxx' for key 'uk_xxx'order_nouser_id + biz_typeUNIQUE KEYNULLNULL != NULLNULLSELECT + INSERTuser_id = 1001UNIQUEsharding_keypay_nopay_noINSERT IGNOREON DUPLICATE KEY UPDATETinyIDLeafglobal_unique_mapINSERT INTO global_unique_map ... ON DUPLICATE KEY UPDATEUNIQUE INDEXINSERTSELECTREAD COMMITTEDREPEATABLE READSELECTnext-key lockDuplicate entryER_DUP_ENTRY