领券功能引入分布式锁
引入redisson依赖
This commit is contained in:
parent
78470e4279
commit
55024f78c0
10
pom.xml
10
pom.xml
@ -75,7 +75,6 @@
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<!--mybatis plus和springboot整合-->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
@ -93,7 +92,6 @@
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
@ -110,7 +108,6 @@
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<!--接口文档依赖-->
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
@ -138,6 +135,13 @@
|
||||
<artifactId>jjwt</artifactId>
|
||||
<version>0.7.0</version>
|
||||
</dependency>
|
||||
<!-- 分布式锁 -->
|
||||
<dependency>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson</artifactId>
|
||||
<version>3.10.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
@ -102,6 +102,12 @@
|
||||
<version>0.7.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- redisson -->
|
||||
<dependency>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
|
@ -0,0 +1,49 @@
|
||||
package net.jieyuu.config;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
import org.redisson.Redisson;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.redisson.config.Config;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@Data
|
||||
public class AppConfig {
|
||||
|
||||
@Value("${spring.redis.host}")
|
||||
private String redisHost;
|
||||
|
||||
@Value("${spring.redis.port}")
|
||||
private String redisPort;
|
||||
|
||||
@Value("${spring.redis.password}")
|
||||
private String redisPwd;
|
||||
|
||||
/**
|
||||
* 配置分布式锁redisson
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public RedissonClient redissonClient() {
|
||||
Config config = new Config();
|
||||
|
||||
//单机模式
|
||||
config.useSingleServer()
|
||||
.setPassword(redisPwd)
|
||||
.setAddress("redis://" + redisHost + ":" + redisPort);
|
||||
|
||||
//集群模式
|
||||
//config.useClusterServers()
|
||||
//.setScanInterval(2000)
|
||||
//.addNodeAddress("redis://10.0.29.30:6379", "redis://10.0.29.95:6379")
|
||||
//.addNodeAddress("redis://127.0.0.1:6379");
|
||||
|
||||
RedissonClient redisson = Redisson.create(config);
|
||||
return redisson;
|
||||
}
|
||||
|
||||
}
|
@ -2,6 +2,7 @@ package net.jieyuu.mapper;
|
||||
|
||||
import net.jieyuu.model.CouponDO;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@ -15,8 +16,9 @@ public interface CouponMapper extends BaseMapper<CouponDO> {
|
||||
|
||||
/**
|
||||
* 扣减库存
|
||||
*
|
||||
* @param couponId
|
||||
* @return
|
||||
*/
|
||||
int reduceStock(long couponId);
|
||||
int reduceStock(@Param("couponId") long couponId);
|
||||
}
|
||||
|
@ -22,11 +22,16 @@ import net.jieyuu.utils.JsonData;
|
||||
import net.jieyuu.vo.CouponVO;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@ -47,6 +52,9 @@ public class CouponServiceImpl implements CouponService {
|
||||
@Autowired
|
||||
private CouponRecordMapper couponRecordMapper;
|
||||
|
||||
@Autowired
|
||||
private StringRedisTemplate redisTemplate;
|
||||
|
||||
@Override
|
||||
public Map<String, Object> pageCouponActivity(int page, int size) {
|
||||
Page<CouponDO> pageInfo = new Page<>(page, size);
|
||||
@ -80,6 +88,15 @@ public class CouponServiceImpl implements CouponService {
|
||||
public JsonData addCoupon(long couponId, CouponCategoryEnum category) {
|
||||
LoginUser loginUser = LoginInterceptor.threadLocal.get();
|
||||
|
||||
String uuid = CommonUtil.generateUUID();
|
||||
String lockKey = "lock:coupon:" + couponId;
|
||||
//避免锁被误删
|
||||
Boolean lockFlag = redisTemplate.opsForValue().setIfAbsent(lockKey, uuid, Duration.ofMinutes(10));
|
||||
|
||||
if (lockFlag) {
|
||||
log.info("加锁成功:{}", couponId);
|
||||
try {
|
||||
// 执行业务逻辑
|
||||
CouponDO couponDO = couponMapper.selectOne(new QueryWrapper<CouponDO>()
|
||||
.eq("id", couponId)
|
||||
.eq("category", category.name()));
|
||||
@ -97,8 +114,7 @@ public class CouponServiceImpl implements CouponService {
|
||||
couponRecordDO.setId(null);
|
||||
|
||||
//扣减库存 todo
|
||||
int rows = 1;//couponMapper.reduceStock(couponId);
|
||||
|
||||
int rows = couponMapper.reduceStock(couponId);
|
||||
if (rows == 1) {
|
||||
//扣减库存成功才保存记录
|
||||
couponRecordMapper.insert(couponRecordDO);
|
||||
@ -106,7 +122,21 @@ public class CouponServiceImpl implements CouponService {
|
||||
log.warn("发放优惠券错误:{},用户:{}", couponDO, loginUser);
|
||||
throw new BizException(BizCodeEnum.COUPON_NO_STOCK);
|
||||
}
|
||||
|
||||
} finally {
|
||||
// 释放锁
|
||||
// 使用lua脚本保证 查询和删除的原子性
|
||||
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
|
||||
Integer result = redisTemplate.execute(new DefaultRedisScript<>(script, Integer.class), Arrays.asList(lockKey), uuid);
|
||||
log.info("解锁{}", result);
|
||||
}
|
||||
} else {//加锁失败
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
log.error("自旋失败");
|
||||
}
|
||||
addCoupon(couponId, category);
|
||||
}
|
||||
return JsonData.buildSuccess();
|
||||
}
|
||||
|
||||
|
@ -24,4 +24,9 @@
|
||||
id, category, publish, coupon_img, coupon_title, price, user_limit, start_time, end_time, publish_count, stock, create_time, condition_price
|
||||
</sql>
|
||||
|
||||
<!--扣减库存-->
|
||||
<update id="reduceStock">
|
||||
update coupon set stock=stock-1 where id = #{couponId} and stock > 0
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
|
Loading…
Reference in New Issue
Block a user