分布式非公平锁实现、路径参数正则表达式修改增强

main
youHong.ai 2022-12-11 16:51:14 +08:00
parent 50989aa997
commit 2d4bce9513
7 changed files with 623 additions and 66 deletions

View File

@ -3459,9 +3459,11 @@ public class Util extends weaver.general.Util {
key:hah
value:haode*/
// 最终通过反射调用weaver.aiyh_jitu.pushdata.service.GetAssignProcessorProcessorImpl类将参数传递给这个类
// String pattern = "&?(?<key>([#.\\w\\u4E00-\\u9FA5]+))=(?<value>((#(\\{|sql\\{))?([()\\-$#={ }.\\w\\u4E00-\\u9FA5?]+)?}?))&?";
//String pattern = "&?(?<key>([#.\\w\\u4E00-\\u9FA5]+))=" +
// "(?<value>(`([\\s():/\\t\\-&*'?$#={ }.\\w\\u4E00-\\u9FA5]*)`|" +
// "((#(\\{|sql\\{))?([():/\\-$#={ }.\\w\\u4E00-\\u9FA5?]+)?}?)))&?";
String pattern = "&?(?<key>([#.\\w\\u4E00-\\u9FA5]+))=" +
"(?<value>((`([():/\\-&?$#={ }.\\w\\u4E00-\\u9FA5?]*)`)|" +
"(?<value>(`([^`]*)`|" +
"((#(\\{|sql\\{))?([():/\\-$#={ }.\\w\\u4E00-\\u9FA5?]+)?}?)))&?";
Pattern compile = Pattern.compile(pattern);
Matcher matcher = compile.matcher(paramStr);
@ -3470,6 +3472,9 @@ public class Util extends weaver.general.Util {
while (matcher.find()) {
String key = matcher.group("key");
String paramValue = matcher.group("value");
if (paramValue.startsWith("`") && paramValue.endsWith("`")) {
paramValue = paramValue.substring(1, paramValue.length() - 1);
}
pathParamMap.put(key, paramValue);
}
return pathParamMap;

View File

@ -0,0 +1,27 @@
package aiyh.utils.lock;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* <h1></h1>
*
* <p>create: 2022-12-11 02:07</p>
*
* @author youHong.ai
*/
@Getter
@Setter
@ToString
public class LockEntity {
/** 锁住次数 */
private Integer times;
/** 锁标识 */
private Thread lockMark;
/** 过期时间 */
private Long expirationTime;
}

View File

@ -0,0 +1,33 @@
package aiyh.utils.lock;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* <h1></h1>
*
* <p>create: 2022-12-11 00:24</p>
*
* @author youHong.ai
*/
@Setter
@Getter
@ToString
public class LockPojo {
/**
* id
*/
private Integer id;
/** 过期时间 */
private Long expirationTime;
/** 锁的键 */
private String lockName;
/** 锁状态 */
private Integer lockStatus;
}

View File

@ -0,0 +1,129 @@
package aiyh.utils.lock;
import aiyh.utils.annotation.recordset.ParamMapper;
import aiyh.utils.annotation.recordset.Select;
import aiyh.utils.annotation.recordset.SqlMapper;
import aiyh.utils.annotation.recordset.Update;
/**
* <h1></h1>
*
* <p>create: 2022-12-11 00:22</p>
*
* @author youHong.ai
*/
@SqlMapper
public interface LockUtilMapper {
/**
* <h2></h2>
* <i>2022/12/11 00:37</i>
* ******************************************
*
* @param lockKey
* @return LockPojo
* @author youHong.ai ******************************************
*/
@Select("select id, lock_name, lock_status, expiration_time " +
"from uf_cus_lock " +
"where lock_name = #{lockKey}")
LockPojo selectLock(@ParamMapper("lockKey") String lockKey);
/**
* <h2></h2>
* <i>2022/12/11 00:46</i>
* ******************************************
*
* @param id id
* @return boolean
* @author youHong.ai ******************************************
*/
@Update("update uf_cus_lock " +
"set lock_status = 0 " +
"where id = #{id} " +
" and lock_status = 1")
boolean unLock(@ParamMapper("id") Integer id);
/**
* <h2></h2>
* <i>2022/12/11 00:46</i>
* ******************************************
*
* @param lockKey
* @return boolean
* @author youHong.ai ******************************************
*/
@Update("update uf_cus_lock " +
"set lock_status = 0 " +
"where lock_name = #{lockKey} " +
" and lock_status = 1")
boolean unLock(@ParamMapper("lockKey") String lockKey);
/**
* <h2></h2>
* <i>2022/12/11 00:49</i>
* ******************************************
*
* @param id id
* @param lockKey
* @param time
* @return boolean
* @author youHong.ai ******************************************
*/
@Update("update uf_cus_lock " +
"set lock_name = #{lockKey}," +
" expiration_time = #{time}," +
" lock_status = 1 " +
"where id = #{id} " +
" and (lock_status = 0 or expiration_time < #{time})")
boolean lock(@ParamMapper("id") Integer id,
@ParamMapper("lockKey") String lockKey,
@ParamMapper("time") Long time);
/**
* <h2></h2>
* <i>2022/12/11 00:52</i>
* ******************************************
*
* @param lockKey
* @param time
* @return boolean
* @author youHong.ai ******************************************
*/
@Update("update uf_cus_lock " +
"set expiration_time = #{time} " +
"where lock_name = #{lockKey} " +
" and lock_status = 1")
boolean updateLockTime(@ParamMapper("lockKey") String lockKey,
@ParamMapper("time") Long time);
/**
* <h2></h2>
* <i>2022/12/11 15:02</i>
* ******************************************
*
* @param id id
* @param lockKey
* @param time
* @param expirationTime
* @return boolean
* @author youHong.ai ******************************************
*/
@Update("update uf_cus_lock " +
"set lock_name = #{lockKey}, " +
" expiration_time = #{time}, " +
" lock_status = 1 " +
"where id = #{id} " +
" and lock_status = 1 " +
" and expiration_time = #{expirationTime}")
boolean reLock(@ParamMapper("id") Integer id,
@ParamMapper("lockKey") String lockKey,
@ParamMapper("time") Long time,
@ParamMapper("expirationTime") Long expirationTime);
}

View File

@ -0,0 +1,346 @@
package aiyh.utils.lock;
import aiyh.utils.Util;
import aiyh.utils.excention.CustomerException;
import cn.hutool.core.thread.ThreadUtil;
import ebu7common.youhong.ai.bean.Builder;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* <h1></h1>
*
* <p>create: 2022-12-11 00:21</p>
*
* @author youHong.ai
*/
public class LockUtils {
private static final LockUtilMapper mapper = Util.getMapper(LockUtilMapper.class);
private static final Map<String, LockEntity> LOCK_MAP = new HashMap<>();
/** 默认过期时间 10s */
private static final Long DEFAULT_OVERDUE_TIME = 1_000 * 10L;
private static final String UF_CUS_LOCK = "uf_cus_lock";
/**
* <h2></h2>
* <i>2022/12/11 15:40</i>
* ******************************************
*
* @param lockName
* @param reentrant
* @return boolean
* @author youHong.ai ******************************************
*/
public static boolean lock(String lockName, boolean reentrant) {
return lock(lockName, DEFAULT_OVERDUE_TIME, reentrant);
}
/**
* <h2></h2>
* <i>2022/12/11 15:40</i>
* ******************************************
*
* @param lockName
* @param overdueTime
* @param reentrant
* @return boolean
* @author youHong.ai ******************************************
*/
public static boolean lock(String lockName, Long overdueTime, boolean reentrant) {
LockPojo lockPojo = mapper.selectLock(lockName);
if (Objects.isNull(lockPojo) || lockPojo.getId() <= 0) {
return insertLock(lockName, overdueTime);
} else {
// 存在当前的锁的锁名称
if (lockPojo.getLockStatus() == 1) {
// 锁处于锁定状态
return onLock(lockName, overdueTime, reentrant, lockPojo);
} else {
// 处于未锁定状态开始对资源上锁
boolean lock = mapper.lock(lockPojo.getId(), lockName, overdueTime);
if (lock) {
// 锁定成功
LOCK_MAP.put(lockName,
Builder.builder(LockEntity::new)
.with(LockEntity::setTimes, 1)
.with(LockEntity::setLockMark, Thread.currentThread())
.with(LockEntity::setExpirationTime, overdueTime)
.build());
return true;
} else {
// 抢占锁失败
lockPojo = mapper.selectLock(lockName);
return retryGetLock(lockName, overdueTime, lockPojo);
}
}
}
}
/**
* <h2></h2>
* <i>2022/12/11 12:23</i>
* ******************************************
*
* @param lockName
* @param overdueTime
* @param reentrant
* @param lockPojo
* @return boolean
* @author youHong.ai ******************************************
*/
private static boolean onLock(String lockName, Long overdueTime, boolean reentrant, LockPojo lockPojo) {
Long time = lockPojo.getExpirationTime();
if (time > System.currentTimeMillis()) {
// 锁过期了 如果要使锁生效就将日期加长
return lockExpiration(lockName, overdueTime, lockPojo);
} else {
//锁没有过期
return inLockTime(lockName, overdueTime, reentrant);
}
}
/**
* <h2></h2>
* <i>2022/12/11 12:24</i>
* ******************************************
*
* @param lockName
* @param overdueTime
* @param reentrant
* @return boolean
* @author youHong.ai ******************************************
*/
private static boolean inLockTime(String lockName, Long overdueTime, boolean reentrant) {
//判断是否存在本地锁对象中
LockPojo lockPojo = mapper.selectLock(lockName);
if (!LOCK_MAP.containsKey(lockName)) {
// 不是本地锁,不支持可重入,使线程进入等待状态
int n = 0;
return retryGetLock(lockName, overdueTime, lockPojo);
}
// 是本地锁
return getLock(lockName, overdueTime, reentrant);
}
/**
* <h2></h2>
* <i>2022/12/11 15:34</i>
* ******************************************
*
* @param lockName
* @param overdueTime
* @param lockPojo
* @return boolean
* @author youHong.ai ******************************************
*/
private static boolean retryGetLock(String lockName, Long overdueTime, LockPojo lockPojo) {
while (lockPojo.getExpirationTime() > System.currentTimeMillis()) {
// 锁还没过期,使线程休眠
long l = lockPojo.getExpirationTime() - System.currentTimeMillis();
if (l > 10) {
ThreadUtil.safeSleep(l - 10L);
}
// 尝试获取锁
lockExpiration(lockName, overdueTime + l, lockPojo);
}
return true;
}
/**
* <h2></h2>
* <i>2022/12/11 13:57</i>
* ******************************************
*
* @param lockName
* @param overdueTime
* @param reentrant
* @return boolean
* @author youHong.ai ******************************************
*/
private static boolean getLock(String lockName, Long overdueTime, boolean reentrant) {
if (reentrant) {
LockEntity lockEntity = LOCK_MAP.get(lockName);
lockEntity.setTimes(lockEntity.getTimes() + 1);
} else {
LockPojo lockPojo = mapper.selectLock(lockName);
retryGetLock(lockName, overdueTime, lockPojo);
}
return true;
}
/**
* <h2></h2>
* <i>2022/12/11 12:25</i>
* ******************************************
*
* @param lockName
* @param overdueTime
* @return boolean
* @author youHong.ai ******************************************
*/
private static boolean lockExpiration(String lockName, Long overdueTime, LockPojo lockPojo) {
boolean lock = mapper.reLock(lockPojo.getId(), lockName, overdueTime, lockPojo.getExpirationTime());
if (lock) {
//更新锁状态成功
LockEntity lockEntity = Builder.builder(LockEntity::new)
.with(LockEntity::setTimes, 1)
.with(LockEntity::setLockMark, Thread.currentThread())
.with(LockEntity::setExpirationTime, overdueTime)
.build();
LOCK_MAP.put(lockName, lockEntity);
return true;
} else {
// 更新失败,可能是其他服务器抢先获得了锁
LockPojo newLockPojo = mapper.selectLock(lockName);
if (Objects.isNull(newLockPojo)) {
// 锁被释放了
boolean isLock = insertLock(lockName, overdueTime);
if (!isLock) {
throw new CustomerException("can not getLock!");
}
return true;
}
if (newLockPojo.getExpirationTime() > lockPojo.getExpirationTime()) {
// 锁被其他机器抢占
return retryGetLock(lockName, overdueTime, newLockPojo);
}
}
return false;
}
/**
* <h2></h2>
* <i>2022/12/11 12:25</i>
* ******************************************
*
* @param lockName
* @param overdueTime
* @return boolean
* @author youHong.ai ******************************************
*/
private static boolean insertLock(String lockName, Long overdueTime) {
// 没有锁需要新增一条锁记录
String modeId = Util.getModeIdByTableName(UF_CUS_LOCK);
int dataId = Util.getModeDataId(UF_CUS_LOCK, Integer.parseInt(modeId), 1);
long currentTime = System.currentTimeMillis();
Long expirationTime = currentTime + overdueTime;
boolean lock = mapper.lock(dataId, lockName, expirationTime);
if (lock) {
// 锁成功
LockEntity lockEntity = Builder.builder(LockEntity::new)
.with(LockEntity::setTimes, 1)
.with(LockEntity::setLockMark, Thread.currentThread())
.with(LockEntity::setExpirationTime, overdueTime)
.build();
LOCK_MAP.put(lockName, lockEntity);
} else {
// 锁失败
retryLock(dataId, lockName, expirationTime, 0);
}
return true;
}
/**
* <h2></h2>
* <i>2022/12/11 01:39</i>
* ******************************************
*
* @param dataId id
* @param lockName
* @param expirationTime
* @param n
* @author youHong.ai ******************************************
*/
private static void retryLock(int dataId, String lockName, Long expirationTime, int n) {
if (n > 5) {
throw new CustomerException("get lock error! 5 failed attempts to update the database");
}
ThreadUtil.safeSleep((n + 1) * 500);
boolean lock = mapper.lock(dataId, lockName, expirationTime + (n + 1) * 500L);
if (lock) {
// 锁成功
LockEntity lockEntity = Builder.builder(LockEntity::new)
.with(LockEntity::setTimes, 1)
.with(LockEntity::setLockMark, Thread.currentThread())
.with(LockEntity::setExpirationTime, expirationTime + (1 + n) * 500L)
.build();
LOCK_MAP.put(lockName, lockEntity);
} else {
// 锁失败
retryLock(dataId, lockName, expirationTime, n + 1);
}
}
/**
* <h2></h2>
* <i>2022/12/11 15:49</i>
* ******************************************
*
* @param lockKey
* @param expirationTime
* @return boolean
* @author youHong.ai ******************************************
*/
public boolean updateLockTime(String lockKey, Long expirationTime) {
if (!mapper.updateLockTime(lockKey, expirationTime)) {
// 更新失败
int n = 0;
do {
if (n++ > 5) {
return false;
}
} while (!mapper.updateLockTime(lockKey, expirationTime));
}
if (LOCK_MAP.containsKey(lockKey)) {
// 存在本地锁,更新锁信息
LockEntity lockEntity = LOCK_MAP.get(lockKey);
lockEntity.setExpirationTime(expirationTime);
}
return true;
}
/**
* <h2></h2>
* <i>2022/12/11 15:56</i>
* ******************************************
*
* @param lockName
* @author youHong.ai ******************************************
*/
public void unLock(String lockName) {
if (LOCK_MAP.containsKey(lockName)) {
// 存在本地锁
LockEntity lockEntity = LOCK_MAP.get(lockName);
if (!lockEntity.getLockMark().equals(Thread.currentThread())) {
// 并非当前上锁的线程在释放锁
return;
}
Integer times = lockEntity.getTimes();
if (times - 1 == 0) {
boolean unlock = mapper.unLock(lockName);
if (!unlock) {
int n = 0;
do {
if (n++ > 5) {
throw new CustomerException("can not unLock!Failed to release the lock after five attempts");
}
} while (!mapper.unLock(lockName)); // 释放锁失败
}
return;
}
lockEntity.setTimes(lockEntity.getTimes() - 1);
}
}
}

View File

@ -1241,6 +1241,7 @@ public class DealWithMapping extends ToolUtil {
/**
* <h2></h2>
*
* @param responseMappingList
* @param requestRes
* @return
@ -1376,7 +1377,7 @@ public class DealWithMapping extends ToolUtil {
value:haode*/
// 最终通过反射调用weaver.aiyh_jitu.pushdata.service.GetAssignProcessorProcessorImpl类将参数传递给这个类 使用``包裹的字符串会被解析为一个字符串
String pattern = "&?(?<key>([#.\\w\\u4E00-\\u9FA5]+))=" +
"(?<value>((`([():/\\-&$?#={ }.\\w\\u4E00-\\u9FA5?]*)`)|" +
"(?<value>((`([^`]*)`)|" +
"((#(\\{|sql\\{))?([():/\\-$#={ }.\\w\\u4E00-\\u9FA5?]+)?}?)))&?";
Pattern compile = Pattern.compile(pattern);
Matcher matcher = compile.matcher(paramStr);

View File

@ -1,5 +1,6 @@
package youhong.ai.pcn;
import aiyh.utils.Util;
import aiyh.utils.httpUtil.HttpMultipartFile;
import aiyh.utils.httpUtil.ResponeVo;
import aiyh.utils.httpUtil.util.HttpUtils;
@ -108,6 +109,21 @@ public class TestOrganization extends BaseTest {
@Test
public void testStaticLog() {
log.info("哈哈哈好的方式");
String testStr = "slflas.fasjdflaf.fasdf?hah=liuliu&cus=`select? * fr$%&#@!)(<>?/\\{}「」【【】[]~、asfom table where id = '' and teset = #{name}`&niua=卧槽";
Map<String, String> stringStringMap = Util.parseCusInterfacePathParam(testStr);
System.out.println(JSON.toJSONString(stringStringMap));
//String pattern = "&?(?<key>([#.\\w\\u4E00-\\u9FA5]+))=" +
// "(?<value>(`([():/\\-&$#='*{ }.\\w\\u4E00-\\u9FA5?]*)`|((#(\\{|sql\\{))?([():/\\-$#={ }.\\w\\u4E00-\\u9FA5?]+)?}?)))&?";
//String pattern = "=`(?<value>(([\\u4E00-\\u9FA5\\w.'#=?${ }*])*))`";
//String pattern = "&?(?<key>([#.\\w\\u4E00-\\u9FA5]+))=(?<value>(`([():/\\-&?%#\\t\\n='{ }.\\w\\u4E00-\\u9FA5]*)*`))";
//Pattern compile = Pattern.compile(pattern);
//Matcher matcher = compile.matcher(testStr);
//while (matcher.find()) {
// String key = matcher.group("key");
// System.out.println(key);
//String paramValue = matcher.group("value");
//System.out.println(paramValue);
//}
}