应用场景
下单,支付,秒杀,减库存等
主要思想
1 setnx 设置一个kv key可以是lock标示+业务数据id value可以是时间戳
2 expire 设置过期时间
3 delete 释放锁 在业务完成的时候在finall 释放掉锁
主要代码
/**
* 加锁
*
* @param locaName 锁的key
* @param acquireTimeout 获取超时时间
* @param timeout 锁的超时时间
* @return 锁标识
*/
public boolean lockWithTimeout(String locaName,
long acquireTimeout, long timeout) {
try {
// 锁名,即key值
String lockKey = “lock:” + locaName;
// 获取锁的超时时间,超过这个时间则放弃获取锁
long end = System.currentTimeMillis() + acquireTimeout;
String nowTime = String.valueOf(System.currentTimeMillis());
while (System.currentTimeMillis() < end) {
if (redisTemplate.opsForValue().setIfAbsent(lockKey, nowTime)) {
redisTemplate.expire(lockKey, timeout, TimeUnit.MILLISECONDS);
// 返回value值,用于释放锁时间确认
return true;
}
// 返回-1代表key没有设置超时时间,为key设置一个超时时间
if (redisTemplate.getExpire(lockKey) == -1) {
redisTemplate.expire(lockKey, timeout, TimeUnit.MILLISECONDS);
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 释放锁
* @param lockName 锁的key
* @return
*/
public void releaseLock(String lockName) {
String lockKey = "lock:" + lockName;
redisTemplate.delete(lockKey);
}
并发测试
1 数据库一张 产品表纪录库存 一张订单表
2 nginx做负载均衡配置,指向2台tomcat 3 jmeter 启动100个线程 下单购买 一直轮询 请求nginx地址
4 没用分布式锁之前 订单表记录数 一只超出库存数,使用分布式锁后订单数和库存数一致。