旧:原来是用行锁来解决的
select * from 库存表 where id = #{id} for update
现在:在业务代码上加Redisson分布式锁
1.添加maven依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.13.6</version>
</dependency>
2.Redisson配置类
@Data
@Configuration
@ConfigurationProperties(prefix = "spring.redis")
public class RedissonConfig {
private String host;
private String port;
private String password;
@Bean
public RedissonClient redissonClient() {
Config config = new Config();
config.useSingleServer().setAddress("redis://"+host+":"+port).setPassword(password).setDatabase(8);
RedissonClient redisson = Redisson.create(config);
return redisson;
}
}
3.在业务代码上加锁
final String lockKey = new StringBuffer().append(orderId).append("-RedissonLock").toString();
RLock lock = redissonClient.getLock(lockKey);
log.info(StrUtil.format("{}线程获取锁,订单id是:{}", Thread.currentThread().getId(), orderId));
long start = System.currentTimeMillis();
try {
Boolean cacheRes = lock.tryLock(30, 10, TimeUnit.SECONDS);
if (cacheRes) {
//入库方法
in();
}
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
} finally {
if (lock.isLocked() && lock.isHeldByCurrentThread()) {
log.info(StrUtil.format("{}线程释放锁", Thread.currentThread().getId()));
long end = System.currentTimeMillis();
log.info(StrUtil.format("{}线程执行耗时:{}", Thread.currentThread().getId(), end - start));
lock.unlock();
}
}
@Transactional(rollbackFor=Exception.class)
void in();
注意:锁要在事务外面,包着锁,不然会出现数据错乱的问题
测试:使用Jmeter测试下
1.入库测试:这里模拟了3个用户,每一个用户10个线程,前两个用户都是300个,后一个是500个,总共只能入1000,所以后面会有两个请求失败
点击运行按钮,查看结果树,右上角表示运行时间
数据库数据
2.出库测试,一样
运行时间
数据库数据