班车服务

BusController

getCount

这部分缓存,优化的时候采用了Redis的list,发现我用Jmeter测试并发的时候,发现了Redis中出现了非常多的异常数据,我当时还没有找到问题,暂时先采取以下方案,以下方案在并发时候,并没有出现数据异常。

if (redisUtils.hasKey(key)) {

// 如果缓存存在

Object obj = redisUtils.get(key);

log.warn("getCount->redis\n");

// 返回数据

return new ResponseUtil().setData(obj);

}

// 写

if (!redisUtils.hasKey(key)) {

// 如果缓存不存在,就写,注意与数据库数据一致性

redisUtils.set(key, response, RedisConstants.COUNTS_EXPIRE.getTime());

}

getCountDetailById

// 和上面一样

if (redisUtils.hasKey(key)) {

Object obj = redisUtils.get(key);

log.warn("getCountDetailById->redis\n");

return new ResponseUtil().setData(obj);

}

// 这里不判断了,上面已经判断过了

redisUtils.set(key, response, RedisConstants.COUNT_DETAIL_EXPIRE.getTime());

BusServiceImpl

getBus

这里基本没调用过,它是获取班车人物信息的。所以分页查询即可

// MyBatis plus的分页查询

IPage busIPage = new Page<>(request.getCurrentPage(), request.getPageSize());

busIPage = busMapper.selectPage(busIPage, null);

getCount

获取场次列表

// 分页插件,这里自定义分页查询

IPage countIPage = new Page<>(request.getCurrentPage(), request.getPageSize());

QueryWrapper queryWrapper = new QueryWrapper<>();

// 获取时间

String currHours = DateUtil.getHours();

String day = DateUtil.getDay();

System.out.println("当前时间:"+currHours);

System.out.println("当前日期:"+day);

// 判断条件

// 1. 找出符合当前天(比如,5.30)

// 2. 找出大于等于当前时间的场次(比如,数据库8点有一场,目前时间为7点,它就符合)

// 3. 找出状态为getBusStatus的场次,一般是还未发车的场次,(比如0,1)

queryWrapper

.eq("begin_date", day)

.ge("begin_time", currHours)

.eq("bus_status", request.getBusStatus())

.orderByAsc("begin_time");// 时间

countIPage = countMapper.selectCounts(countIPage, queryWrapper);

自定义分页CountMapper接口

public interface CountMapper extends BaseMapper {

/**

*

* @param page

* @param wrapper

* @return

*/

IPage selectCounts(IPage page, @Param(Constants.WRAPPER) Wrapper wrapper);

/**

*

* @param wrapper

* @return

*/

CountDetailDto selectCountDetailById(@Param(Constants.WRAPPER) Wrapper wrapper);

}

xml

SELECT

sc.uuid ,

sc.begin_date ,

sc.begin_time ,

sc.bus_id ,

sc.bus_status,

sc.seat_status

FROM

sb_count sc

${ew.customSqlSegment}

getCountDetailById

查询场次详情信息

// 自定义查询,涉及到联表查询

QueryWrapper wrapper = new QueryWrapper<>();

wrapper.eq("sc.uuid", request.getCountId());

xml

SELECT

sc.uuid ,

sc.bus_id ,

sc.bus_status ,

sc.begin_time ,

sc.begin_date ,

sc.selected_seats ,

sc.price,

sb.driver_name ,

sb.seats_number

FROM

sb_count sc

LEFT JOIN sb_bus sb ON

sc.bus_id = sb.uuid

${ew.customSqlSegment}

repeatSeats

判断座位是否已重复

public boolean repeatSeats(String seats, Long coundId) {

// 查查数据库, 找到座位字段

boolean b = false; // false:不重复,true:重复

try {

Count count = countMapper.selectById(coundId);

// 比如,selectedSeats 是1,2

// dbSeats:"",

// dbSeats:"1,2,3",

// dbSeats: "4,5"

// 前端传来的selectedSeats, 前端判断是否为空,要不然后端也判断一下得了

if (seats.equals("")) {

return true;

}

if (count.getSelectedSeats().equals("")) {

return false;

}

String[] ss = seats.split(",");

String[] cs = count.getSelectedSeats().split(",");

// 这里考虑并发问题

HashSet hashSet = new HashSet<>(Arrays.asList(cs));

for (String s : ss) {

if (hashSet.contains(s)) return true;

}

} catch (Exception e) {

e.printStackTrace();

log.error("selectedSeats", e);

return true; // 异常就算是重复

}

return b;

}

addSeats

if (!StrUtil.isEmpty(selectedSeats)) {

// 这里可以优化,字符串拼接,这样的方式爆内存

// StringBuffer

newSelectedSeats = selectedSeats + "," + newSelectedSeats;

}

filterRepeatSeats

回退座位

Count count = countMapper.selectById(coundId);

String[] ss = seats.split(",");

String[] cs = count.getSelectedSeats().split(",");

// 并发问题,注意

HashSet hashSet = new HashSet<>(Arrays.asList(cs));

for (String s : ss) {

if (hashSet.contains(s)) {

hashSet.remove(s);

}

}

if (hashSet.isEmpty()) {

count.setSelectedSeats("");

}

// 考虑了并发

StringBuffer sb = new StringBuffer();

for (String s : hashSet) {

sb.append(s);

sb.append(",");

}

// 上面的方案可以用String的replace的方法替换,遍历要回退的座位,依次替换即可

count.setSelectedSeats(sb.toString());

countMapper.updateById(count);

看一下String的replace的源码(1.8),感觉遍历还挺多,但的确不用自己去写了

public String replace(char oldChar, char newChar) {

if (oldChar != newChar) {

int len = value.length;

int i = -1;

char[] val = value; /* avoid getfield opcode */

while (++i < len) {

if (val[i] == oldChar) {

break;

}

}

if (i < len) {

char buf[] = new char[len];

for (int j = 0; j < i; j++) {

buf[j] = val[j];

}

while (i < len) {

char c = val[i];

buf[i] = (c == oldChar) ? newChar : c;

i++;

}

return new String(buf, true);

}

}

return this;

}

BusSchedule定时器

这里可以使用redis的延时队列或者RocketMQ的消息队列

schedulChangeBusStatus

/**

* 每天上午7点到晚上21点,每隔30分钟执行一次

*/

@Scheduled(cron = "0 0/30 7-21 * * ?")

private void schedulChangeBusStatus() {

log.warn("schedulChangeBusStatus执行");

busService.schedulChangeBusStatus();

}

看一下业务逻辑

public void schedulChangeBusStatus() {

// 获取时间

String currTime = DateUtil.getHours();

// 获取日期

String day = DateUtil.getDay();

log.warn("schedulChangeBusStatus->目前时间:" + currTime);

log.warn("schedulChangeBusStatus->目前时间:" + day);

System.out.println("目前时间:"+ currTime);

System.out.println("目前时间:"+ day);

QueryWrapper queryWrapper = new QueryWrapper<>();

// 先取出beingtime和now相等的表或者end_time和now相等到表

// 1. 取出当天

// 2. 取出开始时间或者结束时间符合当前时间

queryWrapper

.eq("begin_date", day) // 取出当天

.and(o -> o.eq("begin_time", currTime) // 当前时间

.or()

.eq("end_time", currTime));

List counts = countMapper.selectList(queryWrapper);

log.warn("schedulChangeBusStatus->查询到的:" + counts.toString());

// 开始作妖

for (Count count : counts) {

String busStatus = count.getBusStatus();

String beginTime = count.getBeginTime();

String endTime = count.getEndTime();

if (currTime.equals(beginTime)) {

if (busStatus.equals("0")) { // 沙河空闲

count.setBusStatus("2"); // 沙河->清水河

}

if (busStatus.equals("1")) { // 清水河空闲

count.setBusStatus("3"); // 清水河->沙河

}

count.setSelectedSeats(""); // 清空座位

}

if (currTime.equals(endTime)) {

if (busStatus.equals("2")) { // 沙河->清水河

count.setBusStatus("1"); // 清水河空闲

}

if (busStatus.equals("3")) { // 清水河->沙河

count.setBusStatus("0"); // 沙河空闲

}

}

System.out.println("修改的:" + count);

log.warn("schedulChangeBusStatus->修改的:" + count);

// 写入数据库

countMapper.updateById(count);

}

// 删缓存,这里非常重要...不删后果很严重

String key1 = RedisConstants.COUNTS_EXPIRE + "0";

String key2 = RedisConstants.COUNTS_EXPIRE + "1";

if (redisUtils.hasKey(key1)) {

redisUtils.del(key1);

}

if (redisUtils.hasKey(key2)) {

redisUtils.del(key2);

}

}

这里每隔30分钟扫库进行一次io,这里可以有优化... 假如我使用Redis的延迟队列

在用定时器添加场次的时候,可以将这些场次存入Redis的zset的队列中,元素为场次ID,元素对应的score是出发时间,这样就有17个(定时器每天凌晨添加17个)

还是用定时器轮询,采用每隔半小时轮询一次,我们取出队列中当前时间大于队列中权重的时间的场次ID,开始进行业务逻辑判断(更改场次状态)

更改过后,删除或者更改该场次的score的时间(结束时间)

以此类推,如果是结束时间的话,直接删除该场次id和score。

addCounts

这个项目,没有后台,因此场次需要定时器添加即可

/**

* 每天凌晨0点2分执行

*/

@Scheduled(cron = "0 2 0 * * ? ")

private void addCounts(){

log.warn("addCounts执行");

busService.addCounts();

}

具体的业务逻辑:

public void addCounts() {

// 获取日期

String day = DateUtil.getDay();

// 获取前17个场次

QueryWrapper wrapper = new QueryWrapper<>();

wrapper.last("limit 17");

List counts = countMapper.selectList(wrapper);

// 开始修改 这里可以用java8 的特性, 还不是很熟悉,后期优化一下

for (Count count : counts) {

// 更改日期

count.setBeginDate(day);

// 更改uuid

count.setUuid(UUIDUtils.flakesUUID());

// 清空座位

count.setSelectedSeats("");

// 将走位状态清零

count.setSeatStatus("0");

// 插入

countMapper.insert(count);

}

// 删缓存,不删后果依然很严重

String key1 = RedisConstants.COUNTS_EXPIRE + "0";

String key2 = RedisConstants.COUNTS_EXPIRE + "1";

if (redisUtils.hasKey(key1)) {

redisUtils.del(key1);

}

if (redisUtils.hasKey(key2)) {

redisUtils.del(key2);

}

}

JAVA班车项目_JavaBooks/班车服务.md at master · Aim-Tric/JavaBooks · GitHub相关推荐

  1. Java毕设项目汽车4S服务管理系统(java+VUE+Mybatis+Maven+Mysql)

    Java毕设项目汽车4S服务管理系统(java+VUE+Mybatis+Maven+Mysql) 项目运行 环境配置: Jdk1.8 + Tomcat8.5 + Mysql + HBuilderX(W ...

  2. JAVA商城项目(微服务框架)——第7天nginx+cors解决跨域+品牌+分类查询

    0.学习目标 使用资料搭建后台系统 会使用nginx进行反向代理 实现商品分类查询功能 掌握cors解决跨域 实现品牌查询功能 1.搭建后台管理前端 1.1.导入已有资源 后台项目相对复杂,我们不再从 ...

  3. JAVA商城项目(微服务框架)——第11天 elasticsearch搜索

    0.学习目标 独立安装Elasticsearch 会使用Rest的API操作索引 会使用Rest的API查询数据 会使用Rest的API聚合数据 掌握Spring Data Elasticsearch ...

  4. java毕设项目桂林餐饮服务平台(附源码)

    项目运行 环境配置: Jdk1.8 + Tomcat8.5 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclis ...

  5. think in java第6_think-in-java/6.5 protected.md at master · quanke/think-in-java · GitHub

    6.5 protected 现在我们已理解了继承的概念,protected这个关键字最后终于有了意义.在理想情况下,private成员随时都是"私有"的,任何人不得访问.但在实际应 ...

  6. java项目_好程序员Java分享从入门到服务端项目开发的过程

    好程序员Java分享从入门到服务端项目开发的过程,对于打算入门或者刚刚入门学习Java的人来说,刚开始接触这门学科,往往会觉得不知所措,也会觉得很迷茫.结合前人经验,就从入门到进阶对于Java的学习而 ...

  7. springboot毕设项目社区健康服务系统h9bpy(java+VUE+Mybatis+Maven+Mysql)

    springboot毕设项目社区健康服务系统h9bpy(java+VUE+Mybatis+Maven+Mysql) 项目运行 环境配置: Jdk1.8 + Tomcat8.5 + Mysql + HB ...

  8. springboot毕设项目基于微服务的闪聚支付系统设计vwt4i(java+VUE+Mybatis+Maven+Mysql)

    springboot毕设项目基于微服务的闪聚支付系统设计vwt4i(java+VUE+Mybatis+Maven+Mysql) 项目运行 环境配置: Jdk1.8 + Tomcat8.5 + Mysq ...

  9. Java物流项目第四天 作业中心服务开发(pd-work)

    品达物流TMS项目 第5章 作业中心服务开发(pd-work) 1. 作业中心服务数据模型 本章要开发的是作业中心微服务,对应的maven工程为pd-work.作业中心微服务提供TMS中各种作业.单据 ...

  10. ssm毕设项目智慧民政服务平台xl2r9(java+VUE+Mybatis+Maven+Mysql+sprnig)

    ssm毕设项目智慧民政服务平台xl2r9(java+VUE+Mybatis+Maven+Mysql+sprnig) 项目运行 环境配置: Jdk1.8 + Tomcat8.5 + Mysql + HB ...

最新文章

  1. Consul入门07 - Consul Web界面
  2. 2017年10月07日普及组 蚂蚁
  3. 关于mysql触发器和存储过程的理解
  4. Vista开发之旅:微软开发技术20年回顾
  5. linux 内核模块太大,Linux内核模块文件大小
  6. JavaScript 函数(作用域以及闭包)
  7. Mac 10.12连接iSCSI硬盘软件iSCSI Initiator X
  8. 通俗易懂!视觉slam第十一部分——线性系统和卡尔曼滤波
  9. steam,epic,origin限免游戏推送,持续更新
  10. isprime函数python_Python“函数”之我见
  11. [算法]代码运行时间增长数量级对比 线性级别N vs 线性对数级别 NlgN
  12. Python基础-电子邮件-初识
  13. Kubernetes中pod分类、核心组件、网络模型及kubectl命令使用
  14. CANoe:CAPL周期发送CANFD报文
  15. 序列比对(四)——Smith-Waterman算法之仿射罚分
  16. Java课程设计—学生成绩管理系统(54号童欢)
  17. 天刀手游服务器注册不了,天涯明月刀手游开服常见问题汇总 天涯明月刀手游10月16日开服...
  18. 如何打造完整的客户服务体系?
  19. 20172303 20172322 2017-2018-2 暑假作业 结对编程项目-舒尔特方格(增补:计时器的加入与页面优化)...
  20. 卡尔曼滤波MATLAB实现

热门文章

  1. 一个茴字有三种写法——吐槽C#9.0的Records
  2. 安卓ssr无网络连接_安卓手机不能上网无法链接网络的原因及解决方法
  3. 生成树协议(一)STP协议原理简介:广播风暴、MAC地址表震荡实验、STP工作原理、BPDU简介、STP故障处理
  4. 苹果注册开发者账号过程
  5. 什么是二进制数?二进制数是如何表示计算机信息的?
  6. 法院裁定抖音违规共享用户信息 多闪被勒令删头像、昵称
  7. 切换linux默认桌面,Debian默认桌面再次切换到Gnome
  8. 【多传感器融合定位】【学习汇总】
  9. 任务管理器怎么重启计算机,用任务管理器解决软件假死无需重启电脑
  10. kali 基于虚拟机下载