How to ensure Redis idempotency interface?

There is a small business partner in a recent upgrade, encountered such a problem, we have designed a new account system, users need to apply after the upgrade manually synchronize data over the original account, that require the user to trigger synchronization button to synchronize, because some of the data resided on their local users. Then there is a problem in this process, because if the network problem, the user double clicks the button how to do? Even if we made some client process, during synchronization, you can not click again, but after my recent practice reptiles, and if someone else caught our interface it is still unsafe.

Based on this business scenario, I'll use Redis locked way, limiting the time in the user's request, can not initiate a second request.

image.png

After we enter the request preferred to try to acquire the lock object, then the key to this lock object is actually a user id, if the acquisition is successful, we determine the user time has been synchronized data, if synchronized, you can return directly to prompt the user has been synchronized, if not so direct execution of business logic to synchronize data, and finally release the lock, the lock fails if acquired after entering the method, then it is possible that the first time the request is not over, and then they launched a request, this time is to get less than a lock, there would be no synchronization occurs several times synchronous data appears.

So after with this demand, we have to use this Redis implement the following code. First of all we need to know that we want to introduce a method of Redis.

So we want to do only users with Redis lock object, then it should be unique in Redis, and should not be covered, this method returns true after storage is successful, if the element already exists in the Redis instance, then the direct return false

setIfAbsent(key,value)

But the middle and there is a problem, if after acquiring the lock object, our service hung up, then another request this time is certainly not get the lock, based on consideration of this situation, we should also add an element to the expiration time, prevent hang our services after the emergence of the deadlock problem.

/ **   
* additive element   
*   
* @param Key   
* @param value   
* /  
public void SET (Object Key, Object value) {      
       IF (== null || Key value == null) {          
          return;      
       }      
       redisTemplate.opsForValue () .set (Key, value.toString ());  
/ **   
* If already exists returns false, otherwise it returns to true   
*   
* @param Key   
* @param value   
* @return   
* /  
public Boolean SETNX (Object Key, Object value, expireTime Long, TimeUnit mimeUnit) {      
       IF (== null || Key value == null) {          
          return to false;      
       }     
       return redisTemplate.opsForValue().setIfAbsent(key, value, expireTime, mimeUnit); 
} 
/**  
* 获取数据  
*  
* @param key  
* @return  
*/ 
public Object get(Object key) {     
       if (key == null) {         
          return null;     
       }     
       return redisTemplate.opsForValue().get(key); 
} 
/**  
* 删除  
*  
* @param key  
* @return  
*/ 
public Boolean remove(Object key) {     
       if (key == null) {         
          return false;     
       }     
       return redisTemplate.delete(key);  
         long loseTime = newTime + waitTime;         
/**  
* 加锁  
*   
* @Param Key    
* @param the waitTime latency   
* @param expireTime expiration time   
* /  
public Boolean Lock (String Key, the waitTime Long, Long expireTime) {      
       String value = UUID.randomUUID () toString () the replaceAll (. ". - "," ") .toLowerCase ();      
       Boolean In Flag = SETNX (Key, value, expireTime, TimeUnit.MILLISECONDS);      
       // return a successful attempt to acquire the lock      
       IF (In Flag) {          
          return In Flag;      
       } the else {          
         // acquisition failure          
         // now time          
         Long NewTime = System.currentTimeMillis ();          
         // wait for the expiration time          
         // continue to try to acquire the lock successful return          
         the while (System.currentTimeMillis () <loseTime) {              
         Boolean TestFlag = SETNX (Key, value, expireTime, TimeUnit.MILLISECONDS);             
         IF (TestFlag) {                  
            return TestFlag;              
         }              
         the try {                  
           the Thread.sleep ( 1000);              
         } the catch (InterruptedException E) {                  
                 e.printStackTrace ();              
         }          
      }      
   }      
   return to false;  
 / **   
 * lock release   
 *   
 * @param Key  
 * @return  
 */ 
 public Boolean unLock(Object key) {     
        return remove(key); 
}

Our entire lock code logic has finished, we analyze, the user came after the first call lock attempt to acquire the lock, and lock, lock () method takes three parameters are: key, waitTime if the user is acquired less than a lock, you can wait long after this time will not wait for the last parameter is how long after the lock expired, preventing hung up after the service, a deadlock occurs.

After entering the lock (), to perform a locking operation, if the lock is successful, returns true, then execute the business logic behind us, if acquiring the lock fails, get the current time plus the expiration time set with the current time Compare, if waiting time inside, then try again to acquire the lock until the waiting time has elapsed.


Note : In the settings, we set up in order to prevent a deadlock expiration time, we must pay attention, do not wait to go to the set of elements set the expiration time after the success, because this process is not an atomic operation, so you just set successfully after that, not so successfully set the expiration time, directly linked to the service, so this time it will happen deadlock problem, we have to ensure that the storage element and set the expiration time it must be atomic.

Finally, we write a test class to test

Public void test01 @Test () {      
      String Key = "uid: 12011";      
      Boolean Flag = redisUtil.lock (Key, 10L, 1000L * 60);      
      IF (Flag!) {          
         // acquire the lock failure          
         System.err.println ( "Get locking failure");      
      } the else {          
         // successfully acquire the lock          
         System.out.println ( "lock acquisition success");      
      }      
      // release lock      
      redisUtil.unLock (Key);  
}



Guess you like

Origin blog.51cto.com/14453419/2423155