关于接口的幂等性操作

接口的幂等性分为两大类,第一种是有业务单据号的操作,第二种是没有业务单据号的时候。(利用Token来解决无业务单据号时候的操作)

Delate操作的幂等性

  • 先查询然后再删除保证删除操作只执行一次
 		User user = userMapper.selectByPrimaryKey(userId);
        if(user != null){
            log.info("用户存在,用户ID为:"+userId);
            int i = userMapper.deleteByPrimaryKey(userId);
            return i;
        }
        log.info("用户不存在,用户ID为:"+userId);
        return 0;

Update操作的幂等性

  • 利用乐观锁的方式来进行幂等性的控制
 public int updateUser(User user) {
   	return userMapper.updateUser(user);
 }
<update id="updateUser">
    update t_user
    <set>
      <if test="username != null">
        username = #{username,jdbcType=VARCHAR},
      </if>
      <if test="sex != null">
        sex = #{sex,jdbcType=INTEGER},
      </if>
      <if test="age != null">
        age = #{age,jdbcType=INTEGER},
      </if>
      update_count = update_count + 1,
      version = version + 1
    </set>
    where id = #{id,jdbcType=INTEGER}
    and version = #{version,jdbcType=INTEGER}
  </update>

Insert操作的幂等性

  • 有业务号的insert操作,例如:秒杀,商品ID + 用户ID。
  • 采用分布式锁的形式来进行幂等性的控制。
  • 业务执行完毕之后分布式锁也不必要释放,自动过期释放即可。
  • 没有业务单据号的insert操作,比如用户注册,点击多次。
  • 使用Token操作,保证幂等性。
  • 进入注册页的时候,后台统一生成一个token,然后放在前台的隐藏域当中。
  • 用户在页面进行提交的时候,将Token一起提交后台。
  • 在后台通过Token获取分布式锁,完成insert操作。
  • 执行成功以后,不释放锁,等待过期自动释放。

1.有业务单据号(采用ZK官方推荐分布式锁 Curator)

@Configuration
public class ZKConfig {

    @Bean(initMethod="start",destroyMethod = "close")
    public CuratorFramework getCuratorFramework(){
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
        CuratorFramework client = CuratorFrameworkFactory.newClient("localhost:2181", retryPolicy);
        return client;
    }

}
 @Autowired
 private CuratorFramework zkclient;
 
 public int insertUser(User user) throws Exception {
        InterProcessMutex lock = new InterProcessMutex(zkclient, "/"+user.getUsername());
        boolean isLock = lock.acquire(30, TimeUnit.SECONDS);
        if(isLock){
           return userMapper.insertSelective(user);
        }
        return 0;
}

2.没有业务单据号(采用token的方式)

  @RequestMapping("/register")
    public String register(ModelMap map){
        String token = UUID.randomUUID().toString();
        tokenSet.add(token);
        map.addAttribute("user",new User());
        map.addAttribute("token",token);
        return "user/user-detail";
    }
  • 初始化的页面的时候生成一个token,放入前台隐藏域,后台也保存一份,分布式部署的时候,后台存放token的容器使用分布式缓存Redis即可。
    @RequestMapping("/updateUser")
    public String updateUser(User user,@RequestParam String token) throws Exception {

        Thread.sleep(5000);
        if (user.getId() != null){
            System.out.println("更新用户");
            userService.updateUser(user);
        }else{
            if(tokenSet.contains(token)){
                System.out.println("添加用户");
                userService.insertUser(user,token);
            }else {
                throw new Exception("token不存在");
            }

        }
        return "redirect:/user/userList";
    }
  • 将前台隐藏的token传到后台,并和之前的后台存token的容器中判断是否存在
  public int insertUser(User user,String token) throws Exception {
        InterProcessMutex lock = new InterProcessMutex(zkclient, "/"+token);
        boolean isLock = lock.acquire(30, TimeUnit.SECONDS);
        if(isLock){
           return userMapper.insertSelective(user);
        }
        return 0;
    }
  • 将传过来的token作为分布式锁的key

混合操作的幂等性

  • 混合操作,一个接口包括多种操作
  • 同样可以使用Token的操作
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值