长宁区网站制占酷设计网站官网入口
- 作者: 五速梦信息网
- 时间: 2026年04月20日 05:07
当前位置: 首页 > news >正文
长宁区网站制,占酷设计网站官网入口,南京的电商网站设计,合格的网站设计师需要会什么软件概述 定义#xff1a;一种分布式系统下用来生成全局唯一 ID 的工具 特点 唯一性#xff0c;满足优惠券需要唯一的 ID 标识用于核销高可用#xff0c;随时能够生成正确的 ID高性能#xff0c;生成 ID 的速度很快递增性#xff0c;生成的 ID 是逐渐变大的#xff0c;有利于…概述 定义一种分布式系统下用来生成全局唯一 ID 的工具 特点 唯一性满足优惠券需要唯一的 ID 标识用于核销高可用随时能够生成正确的 ID高性能生成 ID 的速度很快递增性生成的 ID 是逐渐变大的有利于数据库形成索引安全性生成的 ID 无明显规律可以避免间接泄露信息生成量大可满足优惠券订单数据量大的需求 ID 组成部分 符号位1bit永远为0时间戳31bit以秒为单位可以使用69年序列号32bit秒内的计数器支持每秒产生2^32个不同ID 代码实现 目标手动实现一个简单的全局 ID 生成器 实现流程 创建生成器在 utils 包下创建 RedisIdWorker 类作为 ID 生成器创建时间戳创建一个时间戳即 RedisId 的高32位获取当前日期创建当前日期对象 date用于自增 id 的生成count设置 Id 格式保证 Id 严格自增长拼接 Id 并将其返回 代码实现 Component public class RedisIdWorker {// 开始时间戳private static final long BEGIN_TIMESTAMP 1640995200L;// 序列号的位数private static final int COUNT_BITS 32;private StringRedisTemplate stringRedisTemplate;public RedisIdWorker(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate stringRedisTemplate;}// 获取下一个自动生成的 idpublic long nextId(String keyPrefix){// 1.生成时间戳LocalDateTime now LocalDateTime.now();long nowSecond now.toEpochSecond(ZoneOffset.UTC);long timestamp nowSecond - BEGIN_TIMESTAMP;// 3.获取当前日期String date now.format(DateTimeFormatter.ofPattern(yyyy:MM:dd));// 4.获取自增长值生成一个递增计数值。每次调用 increment 方法时它会在这个key之前的自增值的基础上1第一次为0long count stringRedisTemplate.opsForValue().increment(icr: keyPrefix : date);// 5.拼接并返回return timestamp COUNT_BITS | count;} }测试 一、CountDownLatch 工具类 定义信号枪用于同步多线程的等待与唤醒功能 同步多线程的等待与唤醒在异步程序中确保分线程全部走完之后主线程再继续往下执行(如果不用 countdownlatch 则可能分线程还没结束时主线程已经执行完毕)常用方法 await阻塞方法用于主线程中可以让 main 线程阻塞直至 CountDownLatch 内部维护的变量为 0 时再放行countDown计数操作用于分线程中可以让 CountDownLatch 内部变量 -1 操作 二、ExecutorService Executors 定义Java JDK 提供的接口类 功能 简化异步模式下任务的执行自动提供线程池和相关 API执行 Runnable 和 Callable 方法 常用方法 方法说明Executors.newFixedThreadPool(xxxThreads)Executors 提供的工厂方法用于创建 ExecutorService 实例execute(functionName)调用线程执行 functionName 任务无返回值⭐ submit(functionName)调用线程执行 functionName 任务返回一个 Future 类invokeAny(functionName)调用线程执行一组 functionName 任务返回首成功执行的任务的结果invokeAll(functionName)调用线程执行一组 functionName 任务返回所有任务执行的结果⭐ shutdown()停止接受新任务并在所有正在运行的线程完成当前工作后关闭⭐ awaitTermination()停止接受新任务在指定时间内等待所有任务完成 参考资料一文秒懂 Java ExecutorService 代码实现 目标测试 redisIdWorker 在高并发场景下的表现共生成 30000 个 idprivate ExecutorService es Executors.newFixedThreadPool(500); // 创建一个含有 500 个线程的线程池Test void testIdWorker() throws InterruptedException {CountDownLatch latch new CountDownLatch(300); // 定义一个工具类,统计线程执行300次task的进度// 创建函数,供线程执行Runnable task () - {for(int i 0; i 100; i ) {long id redisIdWorker.nextId(order); System.out.println(id id);}latch.countDown();}long begin System.currentTimeMillis();for( int i 0; i 300 ; i ) {es.submit(task);}latch.await(); // 主线程等待直到 CountDownLatch 的计数归long end System.currentTimeMillis();System.out.println(time (end - begin)); // 打印任务执行的总耗时 }超卖问题 一、乐观锁 定义不加锁在更新时判断是否有其他线程修改过数据 优点性能较高 常见的乐观锁CAS (Compare and Swap) 添加库存判断 (分布式环境下仍然存在超卖问题) boolean success seckillVoucherService.update().setSql(stock stock - 1).eq(voucher_id, voucherId).update().gt(stock, 0);二、悲观锁 定义添加同步锁使线程串行执行优点实现简单缺点性能一般 一人一单问题 一、单服务器系统解决方案 需求每个人只能抢购一张大额优惠券避免同一用户购买多张优惠券重点 事务库存扣减操作必须在事务中执行粒度事务粒度必须够小避免影响性能锁事务开启时必须确保拿到当前下单用户的订单并依据用户 Id 加锁找到事务的代理对象避免 Spring 事务注解失效 (需要给启动类加 EnableAspectJAutoProxy(exposeProxy true) 注解)实现逻辑 获取优惠券 id、当前登录用户 id查询数据库的优惠券表voucher_order 如果存在优惠券 id 和当前登录用户 id 都匹配的 order 则拒绝创建订单返回 fail()如果不存在则创建订单 voucherOrder 并保存至 voucher_order 表中返回 ok() 二、分布式系统解决方案 (通过 Lua 脚本保证原子性) 一、优惠券下单逻辑 二、代码实现 (Lua脚本) –1. 参数列表 –1.1. 优惠券id local voucherId ARGV[1] –1.2. 用户id local userId ARGV[2] –1.3. 订单id local orderId ARGV[3]–2. 数据key –2.1. 库存key local stockKey seckill:stock: .. voucherId –2.2. 订单key local orderKey seckill:order .. voucherId–3. 脚本业务 –3.1. 判断库存是否充足 get stockKey if( tonumber( redis.call(get, stockKey) ) 0 ) thenreturn 1 end –3.2. 判断用户是否下单 SISMEMBER orderKey userId if( redis.call( sismember, orderKey, userId ) 1 ) thenreturn 2 end –3.4 扣库存 stockKey 的库存 -1 redis.call( incrby, stockKey, -1 ) –3.5 下单(保存用户) orderKey 集合中添加 userId redis.call( sadd, orderKey, userId ) – 3.6. 发送消息到队列中 redis.call( xadd, stream.orders, *, userId, userId, voucherId, voucherId, id, orderId )三、加载 Lua 脚本 RedisScript 接口用于绑定一个具体的 Lua 脚本DefaultRedisScript 实现类 定义RedisScript 接口的实现类 功能提前加载 Lua 脚本 示例 // 创建Lua脚本对象 private static final DefaultRedisScriptLong SECKILL_SCRIPT;// Lua脚本初始化 (通过静态代码块) static {SECKILL_SCRIPT new DefaultRedisScript();SECKILL_SCRIPT.setLocation(new ClassPathResource(/path/to/lua_script.lua));SECKILL_SCRIPT.setResultType(Long.class); }四、执行 Lua 脚本 调用Lua脚本 API StringRedisTemplate.execute( RedisScriptT script, ListK keys, Object… args )示例 执行 ”下单脚本” 此时不需要 key因为下单时只需要用 userId 和 voucherId 查询是否有锁) Long result stringRedisTemplate.execute(SECKILL_SCRIPT, // 要执行的脚本Collections.emptyList(), // KEYvoucherId.toString(), userId.toString(), String.valueOf(orderId) // VALUES );执行 “unlock脚本” 实战添加优惠券 单服务器创建订单 添加优惠券 目标商家在主页上添加一个优惠券的抢购链接可以点击抢购按钮抢购优惠券 一、普通优惠券 定义日常可获取的资源 代码实现 PostMapping public Result addVoucher(RequestBody Voucher voucher) {voucherService.save(voucher);return Result.ok(voucher.getId()); }二、限量优惠券 定义限制数量需要设置时间限制、面对高并发请求的资源下单流程 查询优惠券通过 voucherId 查询优惠券时间判断判断是否在抢购优惠券的固定时间范围内库存判断判断优惠券库存是否 ≥ 1扣减库存创建订单创建订单 VoucherOrder 对象指定订单号指定全局唯一 voucherId指定用户 id保存订单保存订单到数据库返回结果Result.ok(orderId)代码实现 VoucherController PostMapping(seckill) public Result addSeckillVoucher( RequestBody Voucher voucher ){voucherService.addSeckillVoucher(voucher);return Result.o(voucher.getId()); }VoucherServiceImpl Override Transactional public void addSeckillVoucher(Voucher voucher) {// 保存优惠券到数据库save(voucher);// 保存优惠券信息SeckillVoucher seckillVoucher new SeckillVoucher();seckillVoucher.setVoucherId(voucher.getId());seckillVoucher.setStock(voucher.getStock());seckillVoucher.setBeginTime(voucher.getBeginTime());seckillVoucher.setEndTime(voucher.getEndTime());seckillVoucherService.save(seckillVoucher);// 保存优惠券到Redis中stringRedisTemplate.opsForValue().set(SECKILL_STOCK_KEY voucher.getId(), voucher.getStock().toString()); }(缺陷) 优惠券下单功能 一、功能说明 目标用户抢购代金券保证用户成功获得优惠券保证效率并且避免超卖工作流程 提交优惠券 ID查询优惠券信息 (下单时间是否合法下单时库存是否充足)扣减库存创建订单返回订单 ID 四、代码实现 VoucherOrderServiceImpl (下述代码在分布式环境下仍然存在超卖问题) Service public class VoucherOrderServiceImpl extends ServiceImplVoucherOrderMapper, VoucherOrder implements IVoucherOrderService{Resourceprivate ISeckillVoucherService seckillVoucherService;Overridepublic Result seckillVoucher(Long voucherId) {// 查询优惠券SeckillVoucher voucher seckillVoucherService.getById(voucherId);// 优惠券抢购时间判断if(voucher.getBeginTime().isAfter(LocalDateTime.now) || voucher.getEndTime().isBefore(LocalDateTime.now()){return Result.fail(当前不在抢购时间!);}// 库存判断if(voucher.getStock() 1){return Result.fail(库存不足!);}// !!! 实现一人一单功能 !!!Long userId UserHolder.getUser().getId();synchronized (userId.toString().intern()) {IVoucherOrderService proxy (IVoucherOrderService) AopContext.currentProxy();return proxy.createVoucherOrder(voucherId);}}Transactionalpublic Result createVoucherOrder(Long userId) {Long userId UserHolder.getUser().getId();// 查询当前用户是否已经购买过优惠券int count query().eq(user_id, userId).eq(voucher_id, voucherId).count();if( count 0 ) {return Result.fail(当前用户不可重复购买!);// !!! 实现乐观锁 !!!// 扣减库存boolean success seckillVoucherService.update().setSql(stock stock - 1) // set stock stock - 1;.eq(voucher_id, voucherId).gt(stock, 0) // where voucher_id voucherId and stock 0;.update();if(!success) {return Result.fail(库存不足!);}// 创建订单VoucherOrder voucherOrder new VoucherOrder();voucherOrder.setId(redisIdWorker.nextId(order));voucherOrder.setUserId(UserHolder.getUser().getId());voucherOrder.setVoucherId(voucherId);save(voucherOrder);// 返回订单idreturn Result.ok(orderId); }
- 上一篇: 长宁区科技网站建设网站文明建设工程包括
- 下一篇: 长沙 外贸网站建设公司上海市建设工程材料网站
相关文章
-
长宁区科技网站建设网站文明建设工程包括
长宁区科技网站建设网站文明建设工程包括
- 技术栈
- 2026年04月20日
-
长宁区科技网站建设免费网站推广服务
长宁区科技网站建设免费网站推广服务
- 技术栈
- 2026年04月20日
-
长乐市建设局网站传奇网站怎么制作教程
长乐市建设局网站传奇网站怎么制作教程
- 技术栈
- 2026年04月20日
-
长沙 外贸网站建设公司上海市建设工程材料网站
长沙 外贸网站建设公司上海市建设工程材料网站
- 技术栈
- 2026年04月20日
-
长沙 网站设计 公司为什么网站数量减少
长沙 网站设计 公司为什么网站数量减少
- 技术栈
- 2026年04月20日
-
长沙cms建站模板wordpress会员制订阅
长沙cms建站模板wordpress会员制订阅
- 技术栈
- 2026年04月20日
