前言:
现在小伙伴们对“mysql执行sql语句游戏充值”可能比较关心,朋友们都需要分析一些“mysql执行sql语句游戏充值”的相关内容。那么小编在网上搜集了一些对于“mysql执行sql语句游戏充值””的相关知识,希望你们能喜欢,你们快快来学习一下吧!摘要
每当我们谈起缓存中间件Redis的应用场景时,我们一般都会根据其数据结构联想到对应的应用场景,有序集合SortedSet也不例外,"排行榜"一直都是与其紧密挂钩、不得不谈的其中一种实战场景!本文我们将继续再谈"游戏充值排行榜",介绍如何去处理历史已经存在的充值记录 或者 在将充值记录塞入缓存Cache失败时如何开启后续的补偿处理措施!
内容
在上篇文章中,我们已经给各位小伙伴介绍了如何基于Spring Boot2.0 + 缓存Redis的SortedSet以实际的代码实战一种典型的业务场景"游戏充值排行榜",在文中我们介绍了这一业务场景两大典型的核心功能模块,即"用户充值"、"获取充值排行榜",各位小伙伴可以自行前往回顾!
然而,这世间本就没有十全十美之物,"游戏充值排行榜"这一业务场景也不例外,虽然我们基本上已经实现了该业务场景几乎所有的功能模块,但是我们却忽略了其他两种情况:
A.如果"充值排行榜"这一功能模块是增量式的需求,那么上线时如何去处理历史的用户充值记录呢?你总不能说我们的"充值排行榜"对于以往充值的用户记录不生效吧?(那样岂不令人笑掉大牙!)
B.虽然我们的代码看似完美,但是要知道Bug是无处不在的,这些Bug有的是能一眼被洞穿的,也有的是后知后觉的,"用户充值的过程"便是如此,如果用户充值后插入数据库DB成功、但是插入缓存Cache失败(DB事务不回滚的前提),那毫无疑问,最终得出来的"充值排行榜"一定是不准确的(因为我们是直接从缓存Redis中获取的)!
带着这两大问题,我们给大家提供了一种并非十全十美的,但是却能保证"最终一致性"的充值排行榜的解决方案,那就是万能的定时任务调度!
既然是定时任务调度,那么这个定时任务是做啥的呢?没错,它要完成的任务就是开启一个定时时钟,基于数据库DB中的"用户充值记录表",借助数据库提供的Order By、Group By等查询得出目前为止所有有效用户的"充值排行榜",下面我们以实际的代码进行实战。
(1)直接建立一个定时任务调度类PhoneFareScheduler,并开发相应的方法实现具体的定时任务逻辑,其完整源代码如下所示:
/**补偿机制:手机号码充值排行榜 * @Author:debug (SteadyJack) * @Link: weixin-> debug0868 qq-> 1948831260**/@Componentpublic class PhoneFareScheduler { private static final Logger log= LoggerFactory.getLogger(PhoneFareScheduler.class); @Autowired private PhoneFareMapper phoneFareMapper; @Autowired private RedisTemplate redisTemplate; //时间频度设定为30min,当然啦,具体的设定要根据实际情况而定 @Scheduled(cron = "0 0/30 * * * ?") public void sortFareScheduler(){ log.info("--补偿性手机号码充值排行榜-定时任务"); this.cacheSortResult(); } @Async("threadPoolTaskExecutor") private void cacheSortResult(){ try { ZSetOperations<String,FareDto> zSetOperations=redisTemplate.opsForZSet(); List<PhoneFare> list=phoneFareMapper.getAllSortFares(); if (list!=null && !list.isEmpty()){ redisTemplate.delete(Constant.RedisSortedSetKey2); list.forEach(fare -> { FareDto dto=new FareDto(fare.getPhone()); zSetOperations.add(Constant.RedisSortedSetKey2,dto,fare.getFare().doubleValue()); }); } }catch (Exception e){ log.error("--补偿性手机号码充值排行榜-定时任务-发生异常:",e.fillInStackTrace()); } }}
值得一提的是,在该定时任务调度中我们设定的时间频率为 每30min进行执行一次任务,实现"充值排行榜"的大洗盘!也就是说,如果前端"排行榜"页面数据出现差错,那么其恢复正确的等待时间是30min(因为我们的定时任务就是前往数据库DB,查询获取得到排行榜,当然啦,其前提是保证DB中的数据是正确无误的!)
(2)其中,phoneFareMapper.getAllSortFares() 的作用就是前往数据库Mysql,通过Group By、Order By和SUM等查询得到排行榜,其完整的动态SQL如下所示:
<!--基于数据库的补偿排名机制--> <select id="getAllSortFares" resultType="com.boot.debug.redis.model.entity.PhoneFare"> SELECT phone, SUM(fare) AS fare FROM phone_fare GROUP BY phone ORDER BY fare DESC </select>
除此之外,@Async("threadPoolTaskExecutor") 的作用便是采用"线程池-多线程的方式异步执行定时任务",故而我们需要作一个全局的Config,用于配置线程池-多线程的相关信息:
/**线程池-多线程配置 * @Author:debug (SteadyJack) * @Link: weixin-> debug0868 qq-> 1948831260**/public class ThreadConfig { @Bean("threadPoolTaskExecutor") public Executor threadPoolTaskExecutor(){ ThreadPoolTaskExecutor executor=new ThreadPoolTaskExecutor(); executor.setCorePoolSize(4); executor.setMaxPoolSize(8); executor.setKeepAliveSeconds(10); executor.setQueueCapacity(8); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); return executor; }}
至此,我们已经撸完了"游戏充值排行榜"这一完整业务的"补偿机制"功能代码了,在测试之前,我们先"偷偷"在数据库表phone_fare中新增几条充值记录,代表"以前存在的历史充值记录"或者"插入DB成功,但插入缓存失败的充值记录",如下图所示:
最后我们基于Postman测试一波吧,下面一张图足以说明一切了:
好了,本篇文章我们就介绍到这里了,建议各位小伙伴一定要照着文章提供的样例代码撸一撸,只有撸过才能知道这玩意是咋用的,否则就成了"空谈者"!
对Redis相关技术栈以及实际应用场景实战感兴趣的小伙伴可以前往Debug搭建的技术社区的课程中心进行学习观看:!
其他相关的技术,感兴趣的小伙伴可以私信Debug!
标签: #mysql执行sql语句游戏充值