利用stringRedisTemplate生成唯一的id
package com.hmdp.service.impl;
import com.hmdp.dto.Result;
import com.hmdp.dto.UserDTO;
import com.hmdp.entity.SeckillVoucher;
import com.hmdp.entity.VoucherOrder;
import com.hmdp.mapper.VoucherOrderMapper;
import com.hmdp.service.ISeckillVoucherService;
import com.hmdp.service.IVoucherOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.utils.RedisIdWorked;
import com.hmdp.utils.SimpleRedisLock;
import com.hmdp.utils.UserHolder;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
@SuppressWarnings("all")
@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {
@Autowired
private ISeckillVoucherService seckillVoucherService;
@Autowired
private RedisIdWorked redisIdWorked;
@Autowired
private StringRedisTemplate stringRedisTemplate;
/**
* 限时优惠卷的秒杀
* @param voucherId
* @return
*/
@Override
public Result seckillVoucher(Long voucherId) {
//1.查询优惠卷
SeckillVoucher voucher = seckillVoucherService.getById(voucherId);
if(voucher==null){
//该卷不存在
return Result.fail("秒杀卷不存在");
}
//2.判断在秒杀开始前
//得到秒杀开始时间
LocalDateTime beginTime = voucher.getBeginTime();
if (beginTime.isAfter(LocalDateTime.now())){
//活动尚未开始
return Result.ok("活动尚未开始");
}
//3.判断在秒杀开始后
LocalDateTime endTime = voucher.getEndTime();
if(endTime.isBefore(LocalDateTime.now())){
return Result.ok("活动已经结束");
}
//4.判断库存是否充足
Integer stock = voucher.getStock();
if(stock<1){
return Result.fail("库存不足");
}
UserDTO user = UserHolder.getUser();
Long id = user.getId();
SimpleRedisLock lock = new SimpleRedisLock("order:"+id,stringRedisTemplate);
//尝试获取锁
boolean flag = lock.tryLock(1200L);
if(!flag){
return Result.fail("一个人只能下一单");
}
try {
//如果这个类本身调用是不具备管理事务的,如果使用Spring管理可以控制事务的一致性
//获取一个spring的代理对象
IVoucherOrderService proxy =(IVoucherOrderService) AopContext.currentProxy();
//利用spring代理对象确保事务的一致性
return proxy.createVoucherOrder(voucherId);
} finally {
//释放锁
lock.unlock();
}
}
@Transactional
public Result createVoucherOrder(Long voucherId){
//5.保证一人一单
//5.1用户id
UserDTO user = UserHolder.getUser();
Long id = user.getId();
Integer count = query().eq("user_id", id).eq("voucher_id", voucherId).count();
if(count>0){
return Result.fail("该用户已经购买");
}
//6.扣减库存
seckillVoucherService.update().setSql("stock=stock-1")
.eq("voucher_id",voucherId).gt("stock",0)//stock>0
.update();
//7.创建订单
VoucherOrder voucherOrder = new VoucherOrder();
//7.1订单id
long order = redisIdWorked.nextId("order");
voucherOrder.setId(order);
//7.2用户id
voucherOrder.setUserId(id);
//7.3购买代金卷的id
voucherOrder.setVoucherId(voucherId);
save(voucherOrder);
//8.返回订单id
return Result.ok(order);
}
}
@Autowired
private ISeckillVoucherService seckillVoucherService;
@Autowired
private RedisIdWorked redisIdWorked;
/**
* 限时优惠卷的秒杀
* @param voucherId
* @return
*/
@Transactional//同时操作两张表 保持数据库的一致性
@Override
public Result seckillVoucher(Long voucherId) {
//1.查询优惠卷
SeckillVoucher voucher = seckillVoucherService.getById(voucherId);
if(voucher==null){
//该卷不存在
return Result.fail("秒杀卷不存在");
}
//2.判断在秒杀开始前
//得到秒杀开始时间
LocalDateTime beginTime = voucher.getBeginTime();
if (beginTime.isAfter(LocalDateTime.now())){
//活动尚未开始
return Result.ok("活动尚未开始");
}
//3.判断在秒杀开始后
LocalDateTime endTime = voucher.getEndTime();
if(endTime.isBefore(LocalDateTime.now())){
return Result.ok("活动已经结束");
}
//4.判断库存是否充足
Integer stock = voucher.getStock();
if(stock<1){
return Result.fail("库存不足");
}
UserDTO user = UserHolder.getUser();
Long id = user.getId();
synchronized (id.toString().intern()){//toString会重新开辟一块空间加上intern()方法时会在常量池中找内容相同的字符串
//如果这个类本身调用是不具备管理事务的,如果使用Spring管理可以控制事务的一致性
//获取一个spring的代理对象
IVoucherOrderService proxy =(IVoucherOrderService) AopContext.currentProxy();
//利用spring代理对象确保事务的一致性
return proxy.createVoucherOrder(voucherId);
}
}
@Transactional
public Result createVoucherOrder(Long voucherId){
//5.保证一人一单
//5.1用户id
UserDTO user = UserHolder.getUser();
Long id = user.getId();
Integer count = query().eq("user_id", id).eq("voucher_id", voucherId).count();
if(count>0){
return Result.fail("该用户已经购买");
}
//6.扣减库存
seckillVoucherService.update().setSql("stock=stock-1")
.eq("voucher_id",voucherId).gt("stock",0)//stock>0
.update();
//7.创建订单
VoucherOrder voucherOrder = new VoucherOrder();
//7.1订单id
long order = redisIdWorked.nextId("order");
voucherOrder.setId(order);
//7.2用户id
voucherOrder.setUserId(id);
//7.3购买代金卷的id
voucherOrder.setVoucherId(voucherId);
save(voucherOrder);
//8.返回订单id
return Result.ok(order);
}