码迷,mamicode.com
首页 > 其他好文 > 详细

多条件拦截链如何实现?

时间:2020-07-06 20:06:50      阅读:69      评论:0      收藏:0      [点我收藏+]

标签:自己的   方法   解决   limit   注入   多个   保存   temp   div   

问题提出

  1. 用户参与抽奖,每日只能参与3次,总共只能参与15次,如何控制?(限额)

  2. 给用户发送短信,每天只能发送3条,每条间隔10分钟,如何控制?(防骚扰)

  • 两个问题其实类似 ,都是多个限制条件

以问题2制定方案

  • 使用redis做计数器,使用StringRedisTemplate作为API
  • 使用两个校验器分别校验两个约束
  • 后续添加规则只需要新增校验器
  • 以【dayLimit:用户ID】为key,自增value,如果自增后的值大于3,返回false,否则返回true;过期时间设置为次日0点
  • 以【periodLimit:用户ID】为key,当前时间为value,过期时间设置为10分钟,使用setIfAbsent进行设置。如果设置成功,说明10分钟内没有发送过。如果设置失败,说明10分钟内发送过,获取key的剩余过期时间为短信需要延时时间。

存在问题

  • 第一步如果成功,第二步失败,那么白白消耗了一次每日的限制,需要回滚
  • 如果在第二步失败回滚,那么需要在校验器2里面回滚校验器1,两个步骤产生了强行关联!
  • 校验器1必须在校验器2前面
  • 添加了校验器3,那么就要回滚1和2

如何解决?

  • 合并成一个校验器:优点:类之间不存在依赖性;缺点:不符合开闭原则,比如添加一个规则7天只能发10条,需要继续往这个校验器里面加代码

  • 使用redis的lua脚本,优点:降低了类的依赖性;缺点:逻辑在脚本里面

  • emmmm,好像没有很好的解决方案,这种依赖和回滚必然存在

最后思考

  • 不依赖事务就只能自己回滚了,那就尽量设计下类结构吧
  • 还是按照一个规则一个校验器来写
  • 接口声明校验方法和回滚方法,由具体校验器来实现
  • 接口还要一个getPrevious方法,返回上一个校验器
  • 所有的校验器使用责任链的方式串起来,每个校验器提供一个回滚方法,该方法在下一个校验器不通过时调用,同时,每个校验器还要通过getPrevious调用上一个校验器的回滚方法,达到递归回滚的目的
  • 使用抽象校验器实现getPrevious和调用上一个校验器
  • 这样设计后,每个校验器只需要专注实现自己的校验逻辑以及回滚逻辑
  • 校验器的顺序起来不用必须固定了!
  • emmmm,看起来也符合了开闭原则!

最后的问题

  • 事务,某个校验器执行中宕机,无法回滚。记好日志吧,低概率高成本低损失不值得修复。

收获

  • 最后思考里的设计本来没想到的,打字打到这里突然灵光乍现!解决了多重回滚问题。
  • 写代码的时候发现我的校验器是使用Sping注入到List里面的,调用是通过遍历调用的,那么其实顺序就有了,没有责任链方式的previous关系了
  • 即如果校验器是使用List保存的,那么getPrevious也可以不要了,遍历list的时候使用下标方式,回滚的时候回滚遍历过的校验器就行了

思考<笔记<动手

多条件拦截链如何实现?

标签:自己的   方法   解决   limit   注入   多个   保存   temp   div   

原文地址:https://www.cnblogs.com/zby9527/p/13256454.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!