/**
* @description: 数据库方式实现分布式锁
* @author: 码上得天下
* @create: 2019-12-27 14:33
**/
@RestController
public class LockOCCTest {
@Value("${timertask.min.wait:50}")
private String minWaitStr;
@Value("${timertask.max.wait:500}")
private String maxWaitStr;
@Autowired
LockOCCMapper lockOCCMapper;
@PostMapping(value = "/getLock")
public boolean getLock(@RequestBody Map<String, Object> requestMap){
LockOCCDTO lockDTO = new LockOCCDTO();
lockDTO.setLockName((String) requestMap.get("lockName"));
lockDTO.setLockSeconds((Integer) requestMap.get("lockSeconds"));
lockDTO.setLockUser((String) requestMap.get("lockUser"));
lockDTO.setServerDomain((String) requestMap.get("serverDomain"));
Long tsVersion = (Long) lockOCCMapper.queryLockTimeByLockName((String) requestMap.get("lockName"));
lockDTO.setTsVersion(tsVersion);
Integer lockSeconds = (Integer) requestMap.get("lockSeconds");
//上次时间不存在则添加;
if (null == tsVersion) {
lockOCCMapper.insertLock(lockDTO);
return true;
//间隔时间大于设定则update
} else if (System.currentTimeMillis()/1000 - tsVersion >= lockSeconds) {
// 随机休眠等待,错峰获取锁
this.randomSleep();
int i = lockOCCMapper.updateLock(lockDTO);
//update成功即执行
if (1 == i) {
return true;
//update失败则锁定
} else {
return false;
}
} else {
return true;
}
}
private static int MIN_WAIT = 50;
private static int MAX_WAIT = 500;
private static int INCR_STEP_LENGTH = 20;
private void randomSleep() {
try {
int minWait = MIN_WAIT;
int maxWait = MAX_WAIT;
if(StringUtils.isNotBlank(minWaitStr)){
minWait = Integer.parseInt(minWaitStr);
}
if(StringUtils.isNotBlank(maxWaitStr)){
maxWait = Integer.parseInt(maxWaitStr);
}
int steps = (maxWait - minWait) / INCR_STEP_LENGTH;
Thread.sleep(new SecureRandom().nextInt(steps + 1) * INCR_STEP_LENGTH);
} catch (InterruptedException e) {
}
}
}
@Mapper
public interface LockOCCMapper {
@Select(" SELECT L.TS_VERSION TSVERSION FROM LOCK_OCC_MAS L WHERE LOCK_NAME = #{lockName}")
Long queryLockTimeByLockName(String lockName);
/**秒级时间戳,默认ts_version = 1514736000 */
@Insert(" INSERT INTO LOCK_OCC_MAS(LOCK_NAME, LOCKED_BY, SERVER_DOMAIN) VALUES(#{lockName}, #{lockUser}, #{serverDomain})")
void insertLock(LockOCCDTO lockDTO);
@Update(" update lock_occ_mas l set \n" +
" l.locked_by = #{lockUser},\n" +
" l.server_domain = #{serverDomain},\n" +
" l.ts_version = (sysdate - to_date('1970-1-1 8', 'yyyy-MM-dd hh24')) * 86400,\n" +
" l.date_updated = sysdate\n" +
" where l.lock_name =#{lockName}\n" +
" and l.lock_state = 'Y'\n" +
" and (sysdate - to_date('1970-1-1 8', 'yyyy-MM-dd hh24')) * 86400 - l.ts_version > #{lockSeconds}\n" +
" and l.ts_version = #{tsVersion}")
int updateLock(LockOCCDTO lockDTO);
}
public class LockOCCDTO {
private String lockName;
private int lockSeconds;
private String lockUser;
private String serverDomain;
private Long tsVersion;
public String getLockName() {
return lockName;
}
public void setLockName(String lockName) {
this.lockName = lockName;
}
public int getLockSeconds() {
return lockSeconds;
}
public void setLockSeconds(int lockSeconds) {
this.lockSeconds = lockSeconds;
}
public String getLockUser() {
return lockUser;
}
public void setLockUser(String lockUser) {
this.lockUser = lockUser;
}
public String getServerDomain() {
return serverDomain;
}
public void setServerDomain(String serverDomain) {
this.serverDomain = serverDomain;
}
public Long getTsVersion() {
return tsVersion;
}
public void setTsVersion(Long tsVersion) {
this.tsVersion = tsVersion;
}
@Override
public String toString() {
return "LockOCCDTO [lockName=" + lockName + ", lockSeconds="
+ lockSeconds + ", lockUser=" + lockUser + ", serverDomain="
+ serverDomain + ", tsVersion=" + tsVersion + "]";
}
}