大家都知道在高并发的情况下,商品秒杀可能出现超卖现象,那么今天就针对这个用redisson锁来避免出现这个问题。
首页我是模拟没有锁,任何控制的情况下,用jmeter压测,确实出现超卖。
这代码就是简单获取到商品的秒杀ID然后进行库存的扣减。
利用redisson 分布式锁
<dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>${redisson.version}</version> </dependency>
redisson通用化配置
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
/**
* @Author Lxq
* @Date 2020/12/21 16:19
* @Version 1.0
* redisson通用化配置
*/
@Configuration
public class RedissonConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.port}")
private String port;
@Bean
public RedissonClient redissonClient() {
Config config = new Config();
config.useSingleServer().setAddress("http://" + host + ":" + port);
RedissonClient client = Redisson.create(config);
return client;
}
}
这里有密码的话也可以将密码注入进去。
然后就可以直接使用客户端来调用了,非常方便。
@Autowired private RedissonClient redissonClient;
注入clinet,使用client 创建锁。
注意,锁用完之后一定要释放出去。
使用redisson锁之后确实没有出现超卖现象了,那么我在想,要是这样子做的话,那么我每次都要写这一串东东,有没有更好的方式来实现这个功能呢,于是我尝试用注解 + aop 来实现。
创建自己的注解:RedisLock
import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;
/**
* @Author Lxq
* @Date 2020/12/25 14:18
* @Version 1.0
* 使用redis进行分布式锁
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RedisLock {
/**
* 锁名称
*/
String lockName() default "";
/**
* 锁key
*/
String key() default "";
/**
* 过期时间、默认5秒钟
*/
int expire() default 5000;
/**
* 超时时间单位 秒
*/
TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
}
RedisLockAspect
**
* @Author Lxq
* @Date 2020/12/25 14:24
* @Version 1.0
*/
@Aspect
@Component
public class RedisLockAspect {
@Autowired
private RedissonClient redissonClient;
private static final String REDISSON_LOCK_PREFIX = "redisson_lock:";
@Around("@annotation(redisLock)")
public Object around(ProceedingJoinPoint joinPoint, RedisLock redisLock) throws Throwable {
String key = redisLock.key();
String lockName = redisLock.lockName();
RLock rLock = redissonClient.getLock(REDISSON_LOCK_PREFIX + lockName + key);
rLock.lock(redisLock.expire(), redisLock.timeUnit());
Object result = null;
try {
//执行方法
result = joinPoint.proceed();
} finally {
rLock.unlock();
}
return result;
}
}
然后我在实现类的上面加载自己定义的注解
这样做省事多了,还有就是要注意不要将注解写到接口方法的上面,因为这样子是不会生效的。