我们知道现在微服务很流行,为此,许多中小型企业都将自己以前的框架加以改造,其中以SpringCloud为最多,但是SpringCloud如果要加定时任务的话,在单台服务器上很好支持,
但是涉及到集群服务(多台服务的话)就要用到分布式锁了,最简单的方案是用Redis,好了废话不多说,直接上代码.
1、分布式锁
/**
* 分布式锁
*
*
*/
@Component
public class DistributedLockHandler {
private static final Logger logger = LoggerFactory.getLogger(DistributedLockHandler.class);
/**
* 最大持有锁的时间(毫秒)
*/
private final static long LOCK_EXPIRE = 30 * 1000L;
/**
* 尝试获取锁的时间间隔(毫秒)
*/
private final static long LOCK_TRY_INTERVAL = 30L;
/**
* 获取锁最大等待时间( 毫秒 )
*/
private final static long LOCK_TRY_TIMEOUT = 20 * 1000L;
@Resource(name = "customRedisTemplate")
private RedisTemplate<String, String> template;
/**
* 尝试获取 分布式锁
*
* @param lockKey
* 锁名
* @return true 得到了锁 ,false 获取锁失败
*/
public boolean tryLock(String lockKey) {
return getLock(lockKey, LOCK_TRY_TIMEOUT, LOCK_TRY_INTERVAL, LOCK_TRY_INTERVAL);
}
/**
* 尝试获取 分布式锁(不自动释放锁)
*
* @param lockKey
* 锁名
* @return true 得到了锁 ,false 获取锁失败
*/
public boolean tryLockNotAutoRelease(String lockKey) {
return getLock(lockKey, LOCK_TRY_TIMEOUT, LOCK_TRY_INTERVAL, -1);
}
/**
* 尝试获取 分布式锁
*
* @param lockKey
* 锁名
* @param timeout
* 获取锁最大等待时间
* @return true 得到了锁 ,false 获取锁失败
*/
public boolean tryLock(String lockKey, long timeout) {
return getLock(lockKey, timeout, LOCK_TRY_INTERVAL, LOCK_EXPIRE);
}
/**
* 尝试获取 分布式锁(不自动释放锁)
*
* @param lockKey
* 锁名
* @param timeout
* 获取锁最大等待时间
* @return true 得到了锁 ,false 获取锁失败
*/
public boolean tryLockNotAutoRelease(String lockKey, long timeout) {
return getLock(lockKey, timeout, LOCK_TRY_INTERVAL, -1);
}
/**
* 尝试获取 分布式锁
*
* @param lockKey
* 锁名
* @param timeout
* 获取锁最大等待时间
* @param tryInterval
* 获取锁尝试 时间间隔
* @return true 得到了锁 ,false 获取锁失败
*/
public boolean tryLock(String lockKey, long timeout, long tryInterval) {
return getLock(lockKey, timeout, tryInterval, LOCK_EXPIRE);
}
/**
* 尝试获取 分布式锁(不释放锁)
*
* @param lockKey
* 锁名
* @param timeout
* 获取锁最大等待时间
* @param tryInterval
* 获取锁尝试 时间间隔
* @return true 得到了锁 ,false 获取锁失败
*/
public boolean tryLockNotAutoRelease(String lockKey, long timeout, long tryInterval) {
return getLock(lockKey, timeout, tryInterval, -1);
}
/**
* 尝试获取 分布式锁
*
* @param lockKey
* 锁名
* @param timeout
* 获取锁最大等待时间
* @param tryInterval
* 获取锁尝试 时间间隔
* @param lockExpireTime
* 锁最大持有时间
* @return true 得到了锁 ,false 获取锁失败
*/
public boolean tryLock(String lockKey, long timeout, long tryInterval, long lockExpireTime) {
return getLock(lockKey, timeout, tryInterval, lockExpireTime);
}
/**
* 获取分布式锁
*
* @param lockKey
* 锁名
* @param timeout
* 获取锁最大等待时间
* @param tryInterval
* 获取锁尝试 时间间隔
* @param lockExpireTime
* 锁最大持有时间
* @return true 得到了锁 ,false 获取锁失败
*/
public boolean getLock(String lockKey, long timeout, long tryInterval, long lockExpireTime) {
try {
if (StringUtils.isEmpty(lockKey)) {
return false;
}
long startTime = System.currentTimeMillis();
do {
ValueOperations<String, String> ops = template.opsForValue();
if (ops.setIfAbsent(lockKey, "lockValue")) {
if (lockExpireTime > 0) {
template.expire(lockKey, lockExpireTime, TimeUnit.MILLISECONDS);
}
return true;
}
Thread.sleep(tryInterval);
} while (System.currentTimeMillis() - startTime < timeout);
} catch (InterruptedException e) {
logger.error(e.getMessage());
return false;
}
return false;
}
/**
* 释放锁
*
* @param lockKey
*/
public void unLock(String lockKey) {
if (!StringUtils.isEmpty(lockKey)) {
template.delete(lockKey);
}
}
}
2、 在定时任务中使用
@Component
public class AutoComfirmReceied {
private static final Logger logger = LoggerFactory.getLogger(AutoComfirmReceied.class);
@Resource
OrderService orderService;
@Resource
OrderItemMapper orderItemMapper;
@Autowired
DistributedLockHandler distributedLockHandler;
@Scheduled(cron = "${cron.autoComfirmReceied}")
public void run() {
String lockKey = RedisKeyResolver.getLockkey( "AutoComfirmReceied:run" );;
if( distributedLockHandler.tryLockNotAutoRelease( lockKey ) ) {
try {
runTask();
} catch (Exception e) {
e.printStackTrace();
}finally {
distributedLockHandler.unLock( lockKey );
}
}else {
if( logger.isDebugEnabled() ) {
logger.debug("没有获取锁超时..............");
}
}
}
private void runTask() {
logger.info("3分钟执行一次定时任务" + System.currentTimeMillis());
List<String> orderItemReturnStatus = new ArrayList<>();
orderItemReturnStatus.add(OrderItemReturnStatus.WTH.name());
orderItemReturnStatus.add(OrderItemReturnStatus.YJJ.name());
orderItemReturnStatus.add(OrderItemReturnStatus.YQX.name());
OrderItemExample orderItemExample = new OrderItemExample();
OrderItemExample.Criteria oderc = orderItemExample.createCriteria();
oderc.andIsDelEqualTo(false)
.andOrderStatusEqualTo(OrderItemStatus.SENDED.name())
.andReturnStatusIn(orderItemReturnStatus)
.andShippingStatusEqualTo(OrderItemShippingStatus.YFH.name());
List<OrderItem> orderItemList = orderItemMapper.selectByExample(orderItemExample);
Set<String> set = new HashSet<>();
for (OrderItem orderItem : orderItemList) {
Long sendTime10 = AutoConfirmReceivedDateUtil.getAdd10Day(orderItem.getSendDate(), 10);
Long currentTime = new Date().getTime();
if(currentTime > sendTime10){ //当前时间大于,发货后10天的时间,则确认收货
set.add(orderItem.getLogisticsId() + "," + orderItem.getUserId());
}
}
if(!set.isEmpty()){
for (String orderItem : set) {
String[] item = orderItem.split(",");
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("超过10天自动确认收货,logisticsId:" + item[0] + ",userId:" + item[1]);
orderService.confirmReceive(Long.valueOf(item[0]), Long.valueOf(item[1]));
stringBuffer.append(",成功!");
logger.info(stringBuffer.toString());
}
}
}
}