1. 接口类DistributedLock
/**
* 分布式锁
*/
public interface DistributedLock {
/**
* 加锁方法
*
* @param lockType 锁类型
* @param bizId 业务流水号
* @param expireSeconds 超时时间
* @return true 加锁成功 false加锁失败
*/
boolean lock(DistributedLockTypeEnum lockType, String bizId, int expireSeconds);
/**
* 锁释放.
*
* @param lockType 锁类型
* @param bizId 业务流水号
*/
boolean release(DistributedLockTypeEnum lockType, String bizId);
}
2.DistributedLock的分布式锁实现类
/**
* 基于Tair的分布式锁实现
*
*/
public class TairDistributedLock implements DistributedLock {
/**
* logger
*/
private static final Logger LOGGER = LoggerFactory.getLogger(LoggerNames.BIZ_SERVICE);
/**
* tair client
*/
@Autowired
private TairCacheClient tairCacheClient;
/**
* Lock.
*
* @param lockType the biz type
* @param bizId the biz id
* @param expireSeconds 过期时间
* @return true, if successful
*/
@Override
public boolean lock(DistributedLockTypeEnum lockType, String bizId, int expireSeconds) {
String tairKey = this.getTairKey(lockType, bizId);
try {
/**
* @notice
* 1. 先查一次tair,如果能够查到,说明已有数据存在,直接返回false
* 2. 如果不查询直接调用incr方法,则会导致过期时间被更新,tair锁一直不会失效的问题
*/
Result<DataEntry> result = tairCacheClient.getInteger(tairKey);
if (existLocked(result)) {
LogUtil.warn(LOGGER, " lock already, id={0}, {1}", tairKey, result);
return false;
}
Result<Integer> lockResult = tairCacheClient.incr(tairKey, 1, 0, expireSeconds);
if (lockFailed(lockResult)) {
LogUtil.warn(LOGGER, " lock failed, id={0}, {1}", tairKey, lockResult);
return false;
}
LogUtil.info(LOGGER, " lock succeed, id={0}, {1}", tairKey, lockResult);
} catch (Exception ex) {
LogUtil.error(LOGGER, ex, " lock exception, id=" + tairKey);
return false;
}
return true;
}
/**
* Release.
*
* @param bizType the biz type
* @param bizId the biz id
*/
@Override
public boolean release(DistributedLockTypeEnum bizType, String bizId) {
String tairKey = this.getTairKey(bizType, bizId);
try {
boolean result = tairCacheClient.removeObject(tairKey);
if (!result) {
LogUtil.error(LOGGER, " unlock failed, id=" + tairKey);
return false;
}
LogUtil.info(LOGGER, " unlock succeed, id={0}", tairKey);
} catch (Exception ex) {
ModuleLogUtil.error(LOGGER, ex, " lock exception, id=" + tairKey);
return false;
}
return true;
}
public boolean existLocked(Result<DataEntry> result) {
return result != null && result.getValue() != null && result.getValue().getValue() != null;
}
public boolean lockFailed(Result<Integer> lockResult) {
return null == lockResult || !lockResult.isSuccess() || lockResult.getValue() == null
|| lockResult.getValue() != 1;
}
/**
* 获取tair key
*
* @param lockType
* @param bizId
* @return
*/
public String getTairKey(DistributedLockTypeEnum lockType, String bizId) {
if (lockType != null) {
return OpcoreConstants.APP_NAME + lockType.getCode() + "-" + bizId;
} else {
return bizId;
}
}
}
3.锁类型枚举
/**
* 分布式锁类型
*
*/
public enum DistributedLockTypeEnum {
/** 合同编号 */
CONTRACT_NO("CONTRACT_NO", "合同编号"),
/** 开通任务id */
OPEN_TASK_ID("OPEN_TASK_ID", "开通任务id"),
;
/**
* 类型
*/
private String code;
/**
* 描述
*/
private String desc;
DistributedLockTypeEnum(String code, String desc) {
this.code = code;
this.desc = desc;
}
/**
* 通过枚举<code>code</code>获得枚举
*
* @param code 枚举代码
* @return 枚举对象
*/
public static DistributedLockTypeEnum getByCode(String code) {
for (DistributedLockTypeEnum taskStatusEnum : values()) {
if (taskStatusEnum.getCode().equals(code)) {
return taskStatusEnum;
}
}
return null;
}
/**
* Getter method for property <tt>code</tt>.
*
* @return property value of code
*/
public String getCode() {
return code;
}
/**
* Getter method for property <tt>desc</tt>.
*
* @return property value of desc
*/
public String getDesc() {
return desc;
}
}
4.锁模版类
/**
* 加锁模版
*
*/
public class LockTemplate {
/**
* 执行锁
*
* @param lock
* @param callback
*/
public static <R extends Object> R execute(DistributedLock lock, LockCallback callback) {
String lockId = callback.getLockId();
boolean locked = false;
R result = null;
try {
locked = lock.lock(callback.getTargetType(), lockId, callback.getExpireSeconds());
if (locked) {
result = (R) callback.process();
} else {
result = (R) callback.handleFailed();
}
} finally {
if (locked) {
lock.release(callback.getTargetType(), lockId);
}
}
return result;
}
}
6.锁回调接口
/**
* 锁回调接口
*
*/
public interface LockCallback<R extends Object> {
/**
* 避免小概率不同业务,ID相同的冲突,由使用方决策是否重写。
*
* @return
*/
default DistributedLockTypeEnum getTargetType() {
return DistributedLockTypeEnum.CONTRACT_NO;
}
/**
* 获取锁ID.
*/
String getLockId();
/**
* 锁超时时间 默认超时时间为3秒.
*/
default int getExpireSeconds() {
return OpcoreConstants.COMMON_LOCK_EXPIRE_SECONDS;
}
/**
* 执行业务逻辑.
*/
R process();
/**
* 当没有获取到tair锁时的回调,默认不处理.
*/
default R handleFailed() {
throw new OpcoreException(OpcoreResultCodeEnum.PROCESS_FAILED, "get tair lock faild.");
}
}
使用:
LockTemplate.execute(tairDistributedLock, new LockCallback() {
@Override
public DistributedLockTypeEnum getTargetType() {
return DistributedLockTypeEnum.APPLY_ORDER_ID;
}
@Override
public String getLockId() {
return task.getReferenceId();
}
@Override
public Object process() {
//业务逻辑
return null;
}
});