高并发情况下,防止用户名重复插入的问题,SpringMVC MySQL

hello___world___! 2016-09-17 12:15:41
有一个用户表,字段分别是, id, username, password ,分别记录用户的ID(主键),用户名,和密码。

我的业务逻辑中,要求用户名字段,绝对不能有重复。 否则整个系统就完全乱套了。


我之前的办法是,控制层中,在插入新用户之前,先判断一下这个用户名,是否已经存在?如果已经存在,就报错提示给用户,如果不存在,则执行插入操作。

伪代码如下:

事务开始
if(xxxDao.isUsernameExist("love")){
return "你输入的用户名已被占用,请尝试其他用户名,谢谢!";
/** 使用的SQL语句为:
select * from user where username = 'love'
*/
}else{
xxxDao.insertUser(user);
return "用户注册成功,请返回登录页面登录!";
/** 使用的SQL语句为:
INSERT INTO user(id,username,password) VALUES('xxxx','love','xxxxxxx')
*/
}
事务结束



一开始我自己测试,这段程序运行的灰常完美,什么问题也没有!
但是后来,问题,无情的来了。。。

当有多个人,比如100个人,并发访问的时候,就出现问题了:

这100个同志,同时注册 "love" 这个用户名,那么他们首先执行 if(xxxDao.isUsernameExist("love")) 这条语句,来判断user表里,是不是存在 love 这个用户名,那么他们同时得到的结果,是不存在,可以注册这个用户名,然后紧接着开始执行 INSERT INTO...操作了。 后果就是我的user表里,出现了100个用户名是 love的记录。。。。


这一下就完蛋了。。

那么我想请教一下各位大神,如果我把以上代码稍微做下修改,修改成下面这样:

事务开始
if(xxxDao.isUsernameExist("love")){
return "你输入的用户名已被占用,请尝试其他用户名,谢谢!";
/** 使用的SQL语句为:
select * from user where username = 'love'
*/
}else{
xxxDao.insertUser(user);
return "用户注册成功,请返回登录页面登录!";
/** 使用的SQL语句为:
INSERT INTO user(id,username,password) SELECT 'xxxx','love','xxxxxxx' FROM DUAL WHERE NOT EXISTS ( SELECT * FROM user WHERE username = 'love' )
*/
}
事务结束


这样的话,还会不会存在以上那个并发问题?求大神指点我,尽量的能不用锁就不去用锁,能不去修改事务隔离级别,就尽量不修改,除非实在没办法了
...全文
6324 35 打赏 收藏 转发到动态 举报
写回复
用AI写文章
35 条回复
切换为时间正序
请发表友善的回复…
发表回复
sotondolphin 2020-03-10
  • 打赏
  • 举报
回复
你不用事务管理机制么?
flying~closer 2020-03-10
  • 打赏
  • 举报
回复
应该把你的锁放在事务的外面,分布式就用分布式锁,锁的时候只锁对应的用户名
panzhenxing3152 2020-03-09
  • 打赏
  • 举报
回复 1
三中方案一起加。前段注册请求之后按钮置灰。表字段加唯一索引。后端加分布式锁,锁住是否存在服务
ITjavaman 2020-03-09
  • 打赏
  • 举报
回复
我推荐直接在注册的时候,用第三方缓存(redis),直接锁用户名,然后按你原代码的逻辑
一只三黄鸡 2020-03-05
  • 打赏
  • 举报
回复 1
楼上都是大神级别。
我提个建议:为什么不在注册的时候用户输完用户名或者修改用户名的时候直接做判断,并且直接直观的给予用户信息,该用户名已经存在
然后也可以同时加唯一,再加上sql校验。
前端处理掉一些,代码中逻辑处理一些,sql处理一些,最后又有唯一性保证。客户体验感增加10086,程序并发性也会减少10086
realizemdream 2020-03-04
  • 打赏
  • 举报
回复
游北亮 2020-02-29
  • 打赏
  • 举报
回复
首先,最根本的解决问题的办法,肯定是在数据库建唯一索引,可以保证数据的有效性,这个是必须做的; 同时,代码上也可以做优化,比如不要用ORM方法插入数据,用如下语句插入,没有唯一索引也可以保障数据唯一 :

insert into tb1(f1, username)
select 1,'love' from dual
where not exists(select 1 from tb1 where f2='love')
这个语法,SqlServer、MySql、Oracle都支持。 如果一定要用ORM方法,那么唯一索引是最有效的,除非使用分布式锁, synchronized锁只支持单机,多机部署就没用 了。
Simple Simple 2020-02-29
  • 打赏
  • 举报
回复
引用 27 楼 cwmlow 的回复:
在数据库建唯一约束是简便(lanren)的做法,既然考虑到业务是高并发,为何不妨试试在你的业务逻辑代码里增加一个缓存比如ConcurrentHashMap或者Redis诸如此类 ,获取请求的传参跟缓存里的value值作比较。 不存在就添加进去 存在就直接返回重复(每次连接数据库是要开销的), 然后在验证在数据库中是否重复,不重复插入数据库 并且移除缓存里对应的值。 这样不会锁表也不会影响并发吞吐量。 高并发编程肯定要会考虑性能的优化。

这种方式只适用于单服务器的情况,分布式服务器不适用,https://blog.csdn.net/bajianxiaofendui/article/details/104575350
cwmlow 2019-06-17
  • 打赏
  • 举报
回复
在数据库建唯一约束是简便(lanren)的做法,既然考虑到业务是高并发,为何不妨试试在你的业务逻辑代码里增加一个缓存比如ConcurrentHashMap或者Redis诸如此类 ,获取请求的传参跟缓存里的value值作比较。 不存在就添加进去 存在就直接返回重复(每次连接数据库是要开销的), 然后在验证在数据库中是否重复,不重复插入数据库 并且移除缓存里对应的值。 这样不会锁表也不会影响并发吞吐量。 高并发编程肯定要会考虑性能的优化。
u010103215 2019-06-16
  • 打赏
  • 举报
回复
加唯一约束去解决是会锁表的,性能太低了
  • 打赏
  • 举报
回复
可以加索引 也可以锁表
bichir 2016-09-20
  • 打赏
  • 举报
回复
你们没考虑过数据库唯一约束是杂实现的么,你在逻辑代码中用线程锁都会使并发100的线程阻塞,数据库就不会么。你建一个唯一约束当插入数据时一样会锁表。不是跟应用中逻辑一样了么。还降了操作本表更新删除的效率
toitorse2 2016-09-20
  • 打赏
  • 举报
回复
都是高手,但我感觉还是用唯一标识方便
南猿北辙 2016-09-20
  • 打赏
  • 举报
回复
加唯一性约束是个很简便的方法,但还是要看具体的情况,如果在不改动表的情况下,一般的处理就是加锁
kuangshikeji 2016-09-19
  • 打赏
  • 举报
回复
我想请教一下各位大神,谢谢拜托了
Zerlinda_Li 2016-09-19
  • 打赏
  • 举报
回复
引用 12 楼 qq_21873571 的回复:
[quote=引用 11 楼 xiekuntarena 的回复:] [quote=引用 9 楼 qq_21873571 的回复:] [quote=引用 8 楼 xiekuntarena 的回复:] 加唯一约束不是正解,只能保证数据库不错乱, 但意味着页面将显示注册成功,数据库却没有对应插入那条数据。
不是会有返回的影响的行数吗[/quote] 如果加唯一约束,那你干脆就把判断用户名重复的逻辑去掉,直接用返回的int值来判断好了。[/quote]+1[/quote]虽然数据库加唯一约束,但是去重逻辑我觉得还是可以留下的.这样就不必后头的操作了.毕竟出去并发的情况,重复用户名也还是挺多的.
computerclass 2016-09-19
  • 打赏
  • 举报
回复
数据库表设置 username 为 unique 就可以了,重复插入就会插入失败,只有一个能插入成功 根据返回的异常类型来处理就可以啦
qq_21873571 2016-09-18
  • 打赏
  • 举报
回复
引用 8 楼 xiekuntarena 的回复:
加唯一约束不是正解,只能保证数据库不错乱, 但意味着页面将显示注册成功,数据库却没有对应插入那条数据。
不是会有返回的影响的行数吗
月明星稀灬 2016-09-18
  • 打赏
  • 举报
回复
加唯一约束不是正解,只能保证数据库不错乱, 但意味着页面将显示注册成功,数据库却没有对应插入那条数据。
月明星稀灬 2016-09-18
  • 打赏
  • 举报
回复
在isUsernameExist方法中加一个synchronized锁,可以实现100个人方法但是一个一个通过校验
加载更多回复(15)

81,094

社区成员

发帖
与我相关
我的任务
社区描述
Java Web 开发
社区管理员
  • Web 开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧