JAVA general interface idempotent code implementation

Interface idempotency

Multiple requests from the same user have the same impact on the results as one request, which is called idempotency

Solution: create an anti-heavy table

CREATE TABLE `anti_repeat` (
  `id` int(11) NOT NULL,
  `msg` varchar(255) DEFAULT NULL COMMENT '描述信息',
  `create_date` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

Create a user table mock

CREATE TABLE `t_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `userName` varchar(255) DEFAULT NULL COMMENT '用户名',
  `money` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8
dao
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yujie.model.AntiRepeat;

public interface AntiRepeatDao  extends BaseMapper<AntiRepeat> {
}

----------------------------------------------------------------
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yujie.model.User;

public interface UserDao extends BaseMapper<User>{
}
model
import com.baomidou.mybatisplus.annotation.TableName;

import java.util.Date;

@TableName(value="anti_repeat")
public class AntiRepeat {
    private Integer id;
    private String msg;
    private Date createDate;

    public AntiRepeat(Integer id, String msg) {
        this.id = id;
        this.msg = msg;
    }

    public AntiRepeat(Integer id, String msg, Date createDate) {
        this.id = id;
        this.msg = msg;
        this.createDate = createDate;
    }
get...
set...
}
--------------------------------------------------------------------
import com.baomidou.mybatisplus.annotation.TableName;

import java.io.Serializable;

@TableName(value = "t_user")
public class User implements Serializable {
    private static final long serialVersionUID = -2929599080614903612L;

    private Integer id;
    private String username;
    private Integer money;
get...
set...
}
Controller
@RestController
@RequestMapping("/thread")
public class ThreadController {

    @Autowired
    private UserService userService;

    @RequestMapping("/subtraction")
    public  JsonResult subtraction(String username,int money, int id){
        JsonResult jsonResult= new JsonResult();
       try {
            jsonResult = userService.subtraction(username, money, id);
        }catch (Exception e){
            System.out.println("请勿重复提交 ms:"+new Date().getTime());
            jsonResult.setMsg("请勿重复提交");
            jsonResult.setCode(500);
        }
        return jsonResult;
    }

}

Service

@Service
public class UserServiceImpl implements UserService{

    @Autowired
    private UserDao userDao;
    @Autowired
    private AntiRepeatDao antiRepeatDao;


    @Transactional
    @Override
    public JsonResult subtraction(String username, int money, int id) {
        AntiRepeat antiRepeat = antiRepeatDao.selectById(id);
        if(antiRepeat != null){
           throw new RuntimeException("请勿重复提交");
        }

        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper();
        lqw.eq(User::getUsername,username);
        User user = userDao.selectOne(lqw);
        user.setMoney(user.getMoney()-money);
        int count = userDao.updateById(user);

        JsonResult jsonResult = new JsonResult();
        String str="用户:"+username+"扣减"+money+"金额";
        if(count == 0){
            jsonResult.setMsg(str+"失败");
            jsonResult.setCode(500);
            return jsonResult;
        }
        AntiRepeat antiRepeat1 = new AntiRepeat(id,str+"成功",new Date());
        antiRepeatDao.insert(antiRepeat1);
        System.out.println(str+"成功 ms:"+new Date().getTime());
        return jsonResult;
    }
}

Test link http://localhost:8080/thread/subtraction?username=a&money=10&id=1 0086

Concurrent 100 threads test using JMeter

用户:a扣减10金额成功 ms:1675186191711
请勿重复提交 ms:1675186191717
请勿重复提交 ms:1675186191719
请勿重复提交 ms:1675186191721
请勿重复提交 ms:1675186191723
请勿重复提交 ms:1675186191725
请勿重复提交 ms:1675186191726
请勿重复提交 ms:1675186191728
请勿重复提交 ms:1675186191729
请勿重复提交 ms:1675186191733

In the user table, you can see that user a has successfully reduced from the original 100 yuan to 90 yuan

d8bea07758ed48f4bf212023247dc514.png

                         ​​​​​​​​​​​​​​​​​​ In the anti-heavy table, you can see that there is an additional record with the id of 10086

7cf057b237e14be8a022e72133497661.png

 

总结以上就是保证了接口幂等性,流程:携带用户名和金额以及随机的id发送给后端,
后端防重表进行存储随机id,这个id的生成方式很重要,
同一个页面多次点击前端生成同一个id,只有服务器返回结果后才能改变id,
否则当前页面的id永不变

 

The disadvantage is that the server has not responded to the user when the user clicks the recharge button, and the old id value is stored when the user closes the page. The next time the user opens the browser to recharge, he will find a reminder to submit again. At this time, the return to the status of repeated submission should be redirected. Go to the first page to refresh the id to let the user click the recharge button once. We should do the same. Return to the repeated submission prompt and redirect to the home page. If the user wants to recharge the second time, he must click the recharge button once. The second method can open the browser When random id can also be solved

Guess you like

Origin blog.csdn.net/qq_42058998/article/details/128825877