• 0
  • 0
分享
  • 根据关键字生成唯一顺序号的两种方式——软件测试圈
  • 曼倩诙谐 2021-08-05 10:34:50 字数 3523 阅读 917 收藏 0

  在项目开发中,经常遇到根据给定关键字生成系统唯一顺序号的场景,本文整理了两种不同的实现方式。

  1. 通过数据库加锁方式生成顺序号

  该方案主要通过对数据库中表记录的加锁读写来实现的,该表中的记录对应不同关键字的顺序号生成信息,并且,为了提高生成顺序号的效率,可以一次生成指定步长个数的顺序号并存入本地缓存中。

  该方案首先需要在数据库建立用于生成顺序号的表SEQUENCE_NUMBER,表结构如表1所示:

1.png


表1 表结构

  相应的,定义该表对应的Domain:

public class SequenceNumberDomain{ 
private keyName;//关键字名 
private currentKey; //当前值 
private maxKey; //最大值 
private step; //步长 
//省略get和set方法
}

  其次,需要定义用于存储顺序号生成信息的本地缓存,本地缓存可以通过定义CouncurrentHashMap实现。

  至此,所有的准备工作都已完成,可以进行顺序号的生成了,生成顺序号的主要伪代码如下:

ConcurrentHashMap<String, SequenceNumberDomain> localCache = new ConcurrentHashMap();

  该方法的优点是可以一次生成step个顺序号存入缓存,减少了对数据库的访问次数,而且缓存中只存储了step个顺序号,即使缓存数据丢失,系统最多损失掉step个顺序号,不会导致生成重复的顺序号或者丢失太多顺序号。但是,该方案也具有缺点,首先步长难以确定,步长的设置和系统的并发量有关,若步长太短,且会频繁的访问数据库,降低生成顺序号的效率,若步长过长,则缓存丢失会损失较多顺序号;其次,如果系统是分布式部署,不同服务只能访问自己的数据库,若要生成指定关键字的全系统唯一顺序号,则可能需要通过rpc接口、分布式事务等方式等从表中分别取一定数量且不交叉的顺序号存入各自的本地缓存,实现较为复杂。


  2. 通过redis生成顺序号

  若系统部署了redis服务,则顺序号也可以借助redis的incr命令实现,incr命令是将key中储存的数字值加一,如果key不存在,key的值会先被初始化为0,然后再执行incr操作,而且incr命令为原子操作,不会产生并发问题。

  该方案的伪代码如下:

//key 待生成顺序号的关键字,step 步长
pubilic long getSequenceNumber(Stirng key, int step){ 
//开启事务(代码省略) 
//从本地缓存中获取该key对应的SequenceNumberDomain,若本地缓存没有,则创建新的SequenceNumberDomain放入本地缓存。
SequenceNumberDomain sequenceNumberDomain= localCache.get(key); 
if(sequenceNumberDomain == null){ 
//selectForUpdate 通过 select * from SEQUENCE_NUMBER for update 从数据库查询表中当前key的信息; 
sequenceNumberDomain = SequenceNumberDAO.selectForUpdate(key);   //sequenceNumberDomain为空,说明数据库中SEQUENCE_NUMBER没有这个关键字的记录,需要把该记录插入进去 
if(sequenceNumberDomain==null){ 
sequenceNumberDomain = new SequenceNumberDomain(); 
sequenceNumberDomain.setKeyName(key);     sequenceNumberDomain.setCurrentKey(step + 1);      sequenceNumberDomain.setStep(step);     SequenceNumberDAO.SequenceNumberDAO.insert(sequenceNumberDomain); //将sequenceNumberDomain设置好相关信息存入缓存,由于数据库中没有该关键字的记录,所以缓存中当前值为1,且最大值为step,相当于缓存中存储了从1到step的顺序号。
sequenceNumberDomain.setCurrentKey(1);      sequenceNumberDomain.setMaxKey(step);     sequenceNumberDomain.setStep(step);
localCache.push(key, sequenceNumberDomain); 
//将生成的顺序号返回 
return 1; 
}else { 
//如果数据库中有该关键字对应的记录,则根据该记录生成顺序号,同时更新该记录信息 
long sequenceNumber = sequenceNumberDomain.getCurrentKey();   sequenceNumberDomain.setCurrentKey(sequenceNumber + step);   sequenceNumberDomain.setStep(step);   SequenceNumberDAO.SequenceNumberDAO.update(sequenceNumberDomain); 
//设置缓存中能获取到的顺序号的最大值   sequenceNumberDomain.setMaxKey(sequenceNumber + step - 1);   localCache.push(key, sequenceNumberDomain); 
return sequenceNumber;
 } 
} else {
 //如果缓存中可以获取到该key对应的sequenceNumberDomain且需要的顺序号不超过缓存中的最大顺序号,则直接通过缓存生成顺序号,若需要的顺序号超过缓存中的最大顺序号,则需要从数据库获取该key对应的记录,根据数据库中的信息生成顺序号 
if(sequenceNumberDomain.getCurrentKey()+1<=sequenceNumberDomain.getMaxKey()){ 
long sequenceNumber = sequenceNumberDomain.getCurrentKey()+1 ;   sequenceNumberDomain.setCurrentKey(
sequenceNumberDomain.getCurrentKey()+1);
localCache.push(key,sequenceNumberDomain); 
}else{ 
sequenceNumberDomain = SequenceNumberDAO.selectForUpdate(key);
long sequenceNumber = sequenceNumberDomain.getCurrentKey();   sequenceNumberDomain.setCurrentKey(sequenceNumber + step);   sequenceNumberDomain.setStep(step);   SequenceNumberDAO.SequenceNumberDAO.update(sequenceNumberDomain); 
//设置缓存中能获取到的顺序号的最大值   sequenceNumberDomain.setMaxKey(sequenceNumber + step - 1);     localCache.push(key, sequenceNumberDomain); 
return sequenceNumber;
} 
} 
//结束事务 代码省略 
}

  该方案实现简单,且多个微服务可以访问同一个redis服务,不需要通过rpc接口即可根据关键字生成全系统唯一的顺序号,而且由于redis存取速度非常快,所以即使每次只生成一个顺序号,该方案的效率也会非常高。但是该方案的缺点在于如果redis宕机,则数据可能由于没有及时备份而与磁盘上的数据不一致,导致redis重启后生成的顺序号重复。



作者:王欢   

来源:51Testing软件测试网原创

  • 【留下美好印记】
    赞赏支持
登录 后发表评论
+ 关注

热门文章

    最新讲堂

      • 推荐阅读
      • 换一换
          • 在我们实际开发的过程中,有些场景需要从微信小程序跳转到H5页面,使用web-view组件就可以了;实现的方式也很简单,具体实现方式如下:1、小程序如果要正式发布的话,需要配置业务域名并上传验证文件。域名需要备案好的一级域名。配置HTTPS 证书。进入到小程序后台 https://developers.weixin.qq.com 设置-开发设置 -业务域名载校验文件,并将文件放置在域名根目录下。配置好了以上几步就可以进行正常的跳转了相关配置项,在开发选项中都可以配置,这个根据你项目开发的实际需要配置即可;2、要注意的是,我们在开发的过程中,要在开发者工具中,设置不校验合法域名...
            0 0 1608
            分享
          • 经过艰苦的3技术+1HR面,终于告别0offer了,这是面试测试之前整理的牛友们的面经,答案来着互联网,有不合适的地方请大家指出。技术面中除了问项目,其余80%的问题来自牛友们提供的面经,祝大家找到合适的offer。http和https的区别https协议需要到CA(CertificateAuthority,证书颁发机构)申请证书,一般免费证书较少,因而需要一定费用。http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。http的连接很简单,是无状态的。Https协议是...
            4 5 3722
            分享
          •   就在我们等待英国竞争和市场管理局对微软以 690 亿美元收购动视暴雪的计划发出"同意/不同意"的信号时,一份新的报告称,微软最近对收购计划的修改将不必再经过欧盟的一系列调查。  欧盟监管机构--欧盟委员会早在今年 5 月就批准了微软收购动视暴雪的计划。然而,英国 CMA 于 4 月否决了同一计划,声称这会给微软在云游戏市场带来反竞争优势。  此后,微软向 CMA 提交了一份新计划。微软承诺让育碧通过云流媒体提供当前和未来的动视暴雪游戏。中国软件行业协会已临时批准了这一计划,预计将在 10 月 18 日之前给予最终批准。  有人猜测,由于微软计划的改变,欧盟可能会下令对该...
            0 0 1019
            分享
          •   在一位推特用户关于比尔·盖茨参与OpenAI以及对AI总体看好的推文下,埃隆·马斯克回复称还记得与盖茨的早期会面。马斯克表示,盖茨当时对AI的理解有限,现在依然如此。  在上周发表的一篇博客文章中,盖茨谈到了人工智能将如何改变劳动力、医疗保健和教育。  盖茨写道,2016年以来一直在与OpenAI团队会面,最近的一次会面是在去年9月。目前尚不清楚盖茨以何种身份参与的会面(盖茨在2000年辞去微软首席执行官一职,于2020年离开了微软董事会)。  2015年,马斯克等几位硅谷大牛承诺向OpenAI投资10亿美元,他也是OpenAI的创始人之一。  鉴于特斯拉也需要大量AI技术研究,马斯克出于...
            0 0 998
            分享
          •   前言  无论做什么自动化,测试报告一定要有的,它可以清楚的展示出来我们执行用例的情况。便于查看自动化测试结果内容。安静这边了解目前通过python生成的测试报告分别有:HTMLTestRunner、BeautifulReport 、 pytest-html 和Allure,这几种报告内容都是属于不同的模板,本篇文章主要介绍下这如何生成以上四份报告的过程以及对比情况。  HTMLTestRunner  HTMLTestRunner是Python标准库的unittest模块的扩展。它生成易于使用的HTML测试报告。使用时需要下载,然后放到项目目录中  下载地址:http://tungwaiyi...
            12 12 1841
            分享
      • 51testing软件测试圈微信