使用redis分佈式鎖來保證同一時刻只有一個定時任務在執行

@Scheduled(cron = "0 0/30 ?")
public void UpdateSmsUnList(){
try {
//使用redis分佈式鎖來保證同一時刻只有一個定時任務在執行
if (redisUtil.getLock(Constants.MSG_SMS_UN_REDIS_KEY,"doing job",60



3)) {
logger.info("任務開始執行");
msgSmsUnService.aliyunUpdateSmsUnList();//調用阿里數據服務
msgSmsUnService.unicomUpdateSmsUnList();//調用聯通數據服務
}
} catch (Exception e) {
logger.info("阿里、聯通更新數據異常",e.getMessage().toString());
}
}







Constants 類
  public static final String MSG_SMS_UN_REDIS_KEY = MSG_REDIS_KEY + ":msg_sms_un_list";
redisUtil 工具類

import io.lettuce.core.SetArgs;
import io.lettuce.core.api.async.RedisAsyncCommands;
import io.lettuce.core.cluster.api.async.RedisAdvancedClusterAsyncCommands;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;










import java.nio.charset.StandardCharsets;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;


@Component
public class RedisUtil {

Logger logger = LoggerFactory.getLogger(RedisUtil.class);

@Autowired
// 操作字符串的template,StringRedisTemplate是RedisTemplate的一個子集
private StringRedisTemplate stringRedisTemplate;
@Autowired
// RedisTemplate,可以進行所有的操作
private RedisTemplate<Object, Object> redisTemplate;

private ThreadLocal<String> lockValue = new ThreadLocal<>();

private static final String REDIS_LIB_MISMATCH = "Failed to convert nativeConnection. " +
        "Is your SpringBoot main version > 2.0 ? Only lib:lettuce is supported.";

public void set(String key, String value) {
    stringRedisTemplate.opsForValue().set(key, value);
}

public void set(String key, String value, long time) {
    stringRedisTemplate.opsForValue().set(key, value, time);
}
public void setIfAbsent(String key, String value, long time) {
    stringRedisTemplate.opsForValue().setIfAbsent(key,value,time,TimeUnit.SECONDS);
}
public void set(String key, String value, long time, TimeUnit unit) {
    // 向redis裏存入數據和設置緩存時間
    stringRedisTemplate.opsForValue().set(key, value, time, unit);
}

public String get(String key) {
    return stringRedisTemplate.opsForValue().get(key);
}

public Set<String> getKeys(String pattern) {
    return stringRedisTemplate.keys(pattern);
}

public void delete(String key) {
    stringRedisTemplate.delete(key);
}

public boolean getLock(String key, String value, int expireSeconds) {
    String uuid = UUID.randomUUID().toString();
    try {
        String result = redisTemplate.execute(new RedisCallback<String>() {
            @Override
            public String doInRedis(RedisConnection connection) throws DataAccessException {
                try {
                    Object nativeConnection = connection.getNativeConnection();

                    byte[] keyByte = key.getBytes(StandardCharsets.UTF_8);
                    byte[] valueByte = uuid.getBytes(StandardCharsets.UTF_8);

                    String resultString = "";
                    if (nativeConnection instanceof RedisAsyncCommands) {
                        RedisAsyncCommands command = (RedisAsyncCommands) nativeConnection;
                        resultString = command
                                .getStatefulConnection()
                                .sync()
                                .set(keyByte, valueByte, SetArgs.Builder.nx().ex(expireSeconds));
                    } else if (nativeConnection instanceof RedisAdvancedClusterAsyncCommands) {
                        RedisAdvancedClusterAsyncCommands clusterAsyncCommands = (RedisAdvancedClusterAsyncCommands) nativeConnection;
                        resultString = clusterAsyncCommands
                                .getStatefulConnection()
                                .sync()
                                .set(keyByte, keyByte, SetArgs.Builder.nx().ex(expireSeconds));
                    } else {
                        logger.error(REDIS_LIB_MISMATCH);
                    }
                    return resultString;
                } catch (Exception e) {
                    logger.error("Failed to lock, closing connection", e);
                    closeConnection(connection);
                    return "";
                }
            }
        });
        boolean eq = "OK".equals(result);
        if (eq) {
            lockValue.set(uuid);
        }
        return eq;
    } catch (Exception e) {
        logger.error("Set redis exception", e);
        return false;
    }

}
private void closeConnection(RedisConnection connection) {
    try {
        connection.close();
    } catch (Exception e2) {
        logger.error("close connection fail.", e2);
    }
}

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章