sql重复插入问题

问题

在项目中,由于别人并发的调用接口,导致插入了重复数据

解决方案

1.因为使用多台机器部署,可以使用分布式锁用一台机器处理,对处理的方法加锁或同步关键字,但性能会有很大影响,分布式的优势也没了
2.在MySQL的业务表中,根据业务建立唯一索引,防止数据重复

具体操作

建立唯一索引:

ALTER TABLE table_name ADD UNIQUE index_name (column_list)

程序中处理

如果重复插入,MySQL好像会报数据完整性的错误,到spring中后错误被封装为 DuplicateKeyException,只要在程序中捕获这个异常做相应的处理就可以了。

重复插入语句

建立唯一索引或使用主键primary后,还可以使用MySQL的重复插入语句:ignore, replace, ON DUPLICATE KEY UPDATE

INSERT IGNORE INTO `table_name` (`email`, `phone`, `user_id`) VALUES ('test@163.com', '99999', '9999');

这样当有重复记录就会忽略,执行后返回数字0

REPLACE INTO `table_name`(`col_name`, ...) VALUES (...);

REPLACE的运行与INSERT很相像,但是如果旧记录与新记录有相同的值,则在新记录被插入之前,旧记录被删除。

INSERT INTO `table` (`a`, `b`, `c`) VALUES (1, 2, 3) ON DUPLICATE KEY UPDATE `c`=`c`+1; 

如果行作为新记录被插入,则受影响行的值为1;如果原有的记录被更新,则受影响行的值为2。

这部分具体可参考 http://www.111cn.net/database/mysql/50135.htm

总结

不过实际发现异常处理的时间要比MySQL的重复插入语句慢不少,所以可以的话还是使用MySQL的重复插入语句,不要在程序中去处理;但如果业务原因,可能也不得不在程序中处理,比如重复插入了,也要返回已有数据的主键id。

INNODB中NULL字段使用插曲

在大多数情况下字段设计应该避免使用default null的使用,而使用空字符来代表空。
因为INNODB的索引中会存储NULL,如果一个字段可为NULL,并且在该字段上有索引,索引中会存储NULL,每次索引的时候会额外扫更多的字段。在需要使用唯一索引约束一个字段,但是需要部分字段为空时,空字符串会引起唯一索引冲突,NULL可以在唯一索引中不产生冲突。
可参考文章:http://tomblog.readthedocs.io/en/latest/mysql/INNODB%E4%B8%ADNULL%E4%BD%BF%E7%94%A8.html
Mysql联合唯一索引和空值: http://tomblog.readthedocs.io/en/latest/mysql/INNODB中NULL使用.html

参考资料

MySql避免重复插入记录方法(ignore,Replace,ON DUPLICATE KEY UPDATE)

### 如何在SQL中防止重复记录插入 #### 使用唯一约束 (Unique Constraint) 通过定义唯一约束,可以确保特定列中的值不会重复。当尝试插入违反此约束的数据时,数据库会抛出错误。 ```sql ALTER TABLE table_name ADD CONSTRAINT constraint_name UNIQUE (column_name); ``` 对于已经存在的表,在创建唯一索引之前应该先清理掉已有的重复数据[^1]。 #### 插入前检查是否存在 可以在执行 `INSERT` 操作之前使用 `SELECT` 来验证目标行是否已经存在: ```sql IF NOT EXISTS (SELECT * FROM table_name WHERE column_name = 'value') BEGIN INSERT INTO table_name(column_name) VALUES ('value'); END; ``` 这种方法适用于小型应用或低并发场景;但在高并发环境下可能导致竞态条件(race condition),即两个事务几乎同时读取到不存在某条记录并试图插入相同的新纪录[^2]。 #### 利用ON DUPLICATE KEY UPDATE语法(MySQL特有) 如果是在MySQL环境中工作,则可利用其特有的 `ON DUPLICATE KEY UPDATE` 语句处理潜在冲突情况下的更新操作而不是简单地阻止插入动作发生: ```sql INSERT INTO table_name SET id=last_insert_id(id), name='newname' ON DUPLICATE KEY UPDATE name=VALUES(name); ``` 这里假设 `id` 是主键或者是带有唯一性的字段之一。上述命令会在遇到重复键的时候自动触发对该行其他指定字段(`name`) 的修改而非报错终止整个过程[^3]。 #### 应用存储过程控制逻辑 更复杂的情况下还可以编写自定义函数或者存储过程来实现更加精细的业务规则校验机制,比如基于多个属性组合起来作为匹配依据去决定允许还是拒绝新加入的信息项。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值