摘要:最近在项目上遇到了一个同一账号多终端或者说多用户同时登录导致的重复问题。修改后的伪代码如下同一账号不能同时登录用户不存在当有两个线程进入到,第一个线程会修改版本号并插入,而第二个线程则会因为版本号不一致,抛出异常。
最近在项目上遇到了一个同一账号多终端(或者说多用户)同时登录导致的token重复问题。可以在浏览器相应地做一些防止表单重复提交的操作,比如登录按钮点击一次后变成不可点击的状态,等待服务器的响应之后再恢复成点击状态。不过这也并不能解决同一账号多终端登录的问题。
https://github.com/bluesnail9...
项目中的伪代码如下:User user = getUser(username,password); if(null != user) { String token = findToken(user); if(null != token) { user.deleteToken(user); token = null; } if(null == token){ user.insertNewToken(user); } }else { throw new Exception("用户不存在"); }想一想:
为什么会出现token重复的问题?因为同一账号多用户(或者多终端)同时登录时都进入到了if(null == token)这个语句,所以就向数据库中插入了多个token,但是按道理,一个账号,只能对应一个token。
那如何解决这个问题呢?(1)我开始想到的是做一个同步,用synchronized同步语句块。
User user = getUser(username,password); if(null != user) { //使用synchronized做同步 synchronized(username.intern()){ String token = findToken(user); if(null != token) { user.deleteToken(user); token = null; } if(null == token){ user.insertNewToken(user); } } }else { throw new Exception("用户不存在"); }
synchronized括号里的内容应该写什么呢?User实例(对象)?每个线程的User实例都是不一样的。username变量?试了不起作用。username并不是在编译期就可知的,而是在运行期从浏览器传递到后台。修改成username.intern()是可以成功的,intern()方法会在常量池中查找和创建字符串。
(2)使用锁ReentrantLock做同步
//定义锁 private ReentrantLock lock = new ReentrantLock(); User user = getUser(username,password); if(null != user) { try{ //获取锁 lock.lock(); String token = findToken(user); if(null != token) { user.deleteToken(user); token = null; } if(null == token){ user.insertNewToken(user); } }catch(Exception e) { e.printStackTrace(); }finally { //释放锁 lock.unlock(); } }
注意:定义一个私有公共的ReentrantLock,获取锁是调用lock()方法,释放锁调用unlock()方法。如果对于每一个线程都需要加锁和释放锁,性能会比较低。
(3)使用数据库的乐观锁实现。
在用户表上添加一个表示版本的字段。每次用户登录添加token时,都需要进行版本的比较,只有版本一致时,才进行添加token操作。
修改后的伪代码如下:
User user = getUser(username,password); if(null != user) { String token = findToken(user); if(null != token) { user.deleteToken(user); token = null; } if(null == token){ int version = getUserVersion(user.getId()); if(version == user.getVersion()) { updateVersion(version+1,User); user.insertNewToken(user); }else { throw new Exception("同一账号不能同时登录"); } } }else { throw new Exception("用户不存在"); }
当有两个线程进入到if(null == token),第一个线程会修改版本号并插入token,而第二个线程则会因为版本号不一致,抛出异常。
参考文章:
https://blog.csdn.net/u014653...
https://blog.csdn.net/antony9...
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/71246.html
摘要:生成在控制台中继续输入,生成密钥。将文件夹中的公钥添加到管理平台中,在的个人账户的设置中找到如下界面。添加到暂存区后,我们会发现这两个文件的颜色变为了绿色。在熟悉以后,可能会发现有更加简洁快速的提交修改的使用方法。在开发项目时,往往不是一个人进行项目开发,而通常是以团队的形式进行开发一个新功能,那项目开发是如何进行多人高效协作的呢?在不同的开发阶段,我们遇到各种各样的问题,当遇到这些问题时,...
摘要:微信网页授权,基于适配方案,开发的微信授权方案。项目地址又又又一次来写微信网页授权,一年前写过的微信授权解决方案。 vue微信网页授权,基于vue-cli3.0+webpack 4+vant ui + sass+ rem适配方案+axios,开发的微信授权方案。项目地址:vue-wechat-auth 又又又一次来写微信网页授权,一年前写过的 [vue 微信授权解决方案]。 参考了[v...
摘要:针对这种情况,友户通特定开发了联邦用户中心来支持企业的自有用户中心。友户通支持通过协议使用企业内部的支持协议的用户中心账号进行登录。友户通目前支持标准协议以及友户通自定义协议可供企业集成。 友户通做用友云的用户系统也一年多了,经常听实施、售前等说要私有化部署友户通,原因无非是企业的考虑到用户安全性和单一用户账号的需求。但由于用户管理的复杂性,友户通部署与维护并不容易,因此经常纠结在用户...
摘要:为用户提供授权以允许用户操作非公开资源,有很多种方式。具体的代码根据不同的授权方案而有所不同。使用授权原理利用来验证用户,有两种机制实现。使用来实现用户授权主要用于签发如果有将异步的签名。注意这里的与之前用于签发的应该是同一个。 在很多应用中,我们都需要向服务端提供自己的身份凭证来获得访问一些非公开资源的授权。比如在一个博客平台,我们要修改自己的博客,那么服务端要求我们能够证明 我是...
摘要:本人长期出售超大量微博数据旅游网站评论数据,并提供各种指定数据爬取服务,。如果用户传入伪造的,则新浪微博会返回一个错误。 PS:(本人长期出售超大量微博数据、旅游网站评论数据,并提供各种指定数据爬取服务,Message to YuboonaZhang@Yahoo.com。由于微博接口更新后限制增大,这个代码已经不能用来爬数据了。如果只是为了收集数据可以咨询我的邮箱,如果是为了学习爬虫,...
阅读 2789·2021-09-10 10:50
阅读 2162·2019-08-29 16:06
阅读 3142·2019-08-29 11:02
阅读 1065·2019-08-26 14:04
阅读 2770·2019-08-26 13:24
阅读 2237·2019-08-26 12:16
阅读 507·2019-08-26 10:29
阅读 3015·2019-08-23 18:33