需求介绍
在短链服务中,由于引入了消息队列采取的是冗余双写的解决方案,那么如何才能保证用户A的数据同时在B端消费者和C端消费者都是 先成功插入的呢?
解决方案介绍
1、redis作为分布式锁
2、key代表的是短链码code
3、value代表的是用户账号id

踩过的坑
在消费者端的业务代码和生产者端的业务代码不是同一个线程中的操作,即如果引入了消息队列以后,消费者和生产者是相互独立的, 生产者和消费者唯一的联系就是通过传递的消息来关联,因此生产者端存放在线程中的ThreadLocal中的内容必须显示取出来通过 消息传递给消费者端。
伪代码实现
@Overridepublic boolean handleAddShortLink(EventMessage eventMessage) {// 验证合法性操作 TODOString code = shortLinkComponent.createShortLinkCode(shortLinkAddRequest.getOriginalUrl());//加锁//key1是短链码,ARGV[1]是accountNo,ARGV[2]是过期时间String script = "if redis.call('EXISTS',KEYS[1])==0 then redis.call('set',KEYS[1],ARGV[1]); redis.call('expire',KEYS[1],ARGV[2]); return 1;" +" elseif redis.call('get',KEYS[1]) == ARGV[1] then return 2;" +" else return 0; end;";Long result = redisTemplate.execute(newDefaultRedisScript<>(script, Long.class), Arrays.asList(code), eventMessage.getAccountNo(),100);log.info("分布式锁加锁后的result={}",result);//result!=0表示加锁成功if(result!=0){if(EventMessageType.EVENT_LINK.name().equalsIgnoreCase(messageType)){//查询C端数据库中是否已经存在该短链码ShortLinkDO linkCode = shortLinkManager.findByShortLinkCode(code);if(linkCode==null){log.info("C端不存在这个短链对象,可以插入");//构造短链对象 C端对象 TODO//将短链对象插入数据库shortLinkManager.addShrotLink(shortLinkDO);return true;}return false;}else if(EventMessageType.EVENT_MAPPING.name().equalsIgnoreCase(messageType)){//查询B端数据库中是否已经存在该短链码GroupCodeMappingDO groupCodeMappingDO = mappingManager.findByCode(code,shortLinkAddRequest.getGroupId(),eventMessage.getAccountNo());if(groupCodeMappingDO==null){log.info("B端不存在这个短链对象,可以插入");//构造短链对象 B端对象 TODO//将短链插入数据mappingManager.add(mappingDO);return true;}return false;}}return false;}
文章转载自梁霖编程工具库,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




