Introduction to idempotence

Multiple requests for the same method, with the same parameters and the same path, are guaranteed to succeed only once.

We believe that in daily development, more or less will encounter such problems, such as message repeated consumption, form repeated submission and so on.

In fact, the general idea to solve this kind of problem is setupGlobal id, the following several specific solutions to idempotent are introduced. This involves specific business, so it needs to be analyzed on a case-by-case basis. Here is only a general solution.

  • Front-end check

After clicking the submit button, change the button to disable, but this is not rigorous enough to avoid when using the interface to call the tool.

  • useJVMBuilt-in lock

For example, synchronize or reentrantLock locks a service before proceeding with it. If yes, the service is not executed and the lock is released. If not, the service code is executed, but this method has some overhead.

  • useTokenThe way willTokenStored in theRedisIn the

For example, the new interface needs to be idempotent. Before calling the new interface, obtain the token (store the token in Redis) and bring the token in the new interface. If the existence of the token can be found in Redis, it indicates that the business method has not been executed. Delete the token in Redis. If the query cannot be found, it proves that the token has been processed, and now it is repeated processing.

/** ** Before performing idempotent processing on an interface, the front end needs to get the token, that is, getToken */
@GetMapping("/insert")
public void insert(@RequestParam("username") String username, @RequestParam("token") String token) {
    if(! checkToken(token)) {// Throw the exception or return it
        System.out.println("Token cannot be empty or this operation is repeated!");
        return;
    }
    try {
        // TODO:2021/1/22 Normal services are processed
        insert();
        stringRedisTemplate.delete(token);
    } catch(Exception e) { e.printStackTrace(); }}/** * Issue token */ before executing idempotent
public String getToken(a) {
    String token = UUID.randomUUID().toString();
    stringRedisTemplate.opsForValue().set(token, token, 60 * 3, TimeUnit.SECONDS);
    return token;
}

/** * when calling an idempotent method, check */
public Boolean checkToken(String token) {
    if (StringUtils.isEmpty(token)) {
        return Boolean.FALSE;
    }
    if(! stringRedisTemplate.hasKey(token)) {return Boolean.FALSE;
    }
    return Boolean.TRUE;
}
Copy the code
  • Combine database, add uniqueness constraint

For example, create a unique constraint on a certain field, lock it at the database level, or add a token field to the table (put a constraint on it), and then check whether it exists before each processing, and then operate if it does not exist

Conclusion: The specific requirements are based on the service scenario. For sensitive services, you may need to combine the above scenarios to ensure the final guarantee