使用synchronized锁
package pm.redis1.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import pm.redis1.mapper.CommodityMapper;
import pm.redis1.pojo.Commodity;
/**
* @program: redis1
* @description:
* @author: 平家祥
* @create: 2023-04-25 19:16
**/
@Service
public class CommodityServiceImpl{
@Autowired
CommodityMapper mapper;
public synchronized String comm(Integer id){
Commodity commodity = mapper.selectById(id);
if (commodity.getNumber()>0){
commodity.setNumber(commodity.getNumber()-1);
mapper.updateById(commodity);
System.out.println(commodity.getNumber());
return "减库成功";
}else {
System.out.println("库存不足");
return "删除失败";
}
}
}
使用lock锁
Lock lock = new ReentrantLock();
public String comm(Integer id) {
try {
lock.lock();
Commodity commodity = mapper.selectById(id);
if (commodity.getNumber() > 0) {
commodity.setNumber(commodity.getNumber() - 1);
mapper.updateById(commodity);
System.out.println(commodity.getNumber());
return "减库成功";
} else {
System.out.println("库存不足");
return "删除失败";
}
} finally {
lock.unlock();
}
}
通过jmeter压测
两块代码运行时会有重复的问题
使用redis解决分布式锁
@Autowired
StringRedisTemplate redisTemplate;
public String jianStock(Integer id){
ValueOperations<String, String> forValue = redisTemplate.opsForValue();
Boolean aBoolean = forValue.setIfAbsent("id::" + id, "", 30, TimeUnit.SECONDS);
while (!aBoolean){
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Commodity commodity = mapper.selectById(id);
if (commodity.getNumber() > 0) {
commodity.setNumber(commodity.getNumber() - 1);
mapper.updateById(commodity);
System.out.println(commodity.getNumber());
return "减库成功";
} else {
System.out.println("库存不足");
return "删除失败";
}
} finally {
redisTemplate.delete("id::"+id);
}
}
如果业务代码的执行时间超过了设置的锁的时间,再释放锁资源
使用watchDog机制
每隔10s检测当前线程是否还持有所资源,如果持有则为当前线程延迟。---可以自己设置watchDog机制,---第三方Redission完美的解决分布式锁。
redission完美解决redis超时问题
在主函数上加上bean
@Bean //创建redisson交于spring容器来管理
public RedissonClient redisson() {
Config config = new Config();
config.useSingleServer().setAddress("redis://192.168.223.166:6379");
RedissonClient redisson = Redisson.create(config);
return redisson;
}
使用
@Autowired
RedissonClient redissonClient;
public String jianStock(Integer id){
RLock lock = redissonClient.getLock("id::" + id);
try {
lock.lock(30,TimeUnit.SECONDS);
Commodity commodity = mapper.selectById(id);
if (commodity.getNumber() > 0) {
commodity.setNumber(commodity.getNumber() - 1);
mapper.updateById(commodity);
System.out.println(commodity.getNumber());
return "减库成功";
} else {
System.out.println("库存不足");
return "删除失败";
}
} finally {
lock.unlock();
}
}