数据库设计: 酒店订房模块
我的解决方案
一个思考过程的记录:
大致上分为两种情况:
- 用户预定房间
用户在预定房间时,系统判断当前空房信息,并为其自动分配房间
预定了房间的顾客在入住的时候,直接入住之前分配的房间;如果对自动分配的房间号不满意,可由前台人员为其手动选择一个房间 - 用户没有预定房间直接入住
关键点来了,如何判断用户当前选中的房间类型在某一个时间段内是否还有空房呢?
我的想法是,在用户预定或者入住的时候,将入住的房间号,开始时间,结束时间存入一张表中。在查询空房信息时,输入开始时间和结束时间,向这张表中查询。
虽然在写Service层的时候有点头大,但终归是写出来了
具体说明篇幅有点长, 这里不过多赘述
最后的数据库ER图是这样的
老师的解决方案
老师的解决方法是真的妙,用了一个空房日历表就解决了
利用定时事务,将所有房间类型和对应时间的空房数量存入一个空房日历表
最后的ER图
接口:查询空房信息
数据准备
首先我在房型表中准备了三条数据
接着在套餐表中准备了几条数据(注:我的套餐表命名是solution,老师的好像是叫room_price)
最后在空房日历表中准备了几条数据
由于三张表的关系是这样的
三张表连接之后的数据量庞大,所以这里不使用多表连接的方式来查询数据
注意!我们的数据库表的名称不一定完全一样!
model层
套餐实体类
@Data
public class Solution {
private Integer solutionID;
private String solutionName;
private Integer roomTypeID;
private String breakfastType;
private Double solutionPrice;
}
房型实体类
@Data
public class RoomType {
private Integer roomTypeID;
private String roomTypeName;
private String roomTypeDesc;
private String bedType;
private String wifiType;
private Integer startFloor;
private Integer endFloor;
}
空房日历实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FreeRoomCalendar {
private Integer freeRoomCalendarID;
private Integer roomTypeID;
private Date calendarDate;
private Integer totalCount;
private Integer freeCount;
private Integer minFreeCount;
}
controller层
首先分析业务逻辑:
用户输入入住日期和退房日期, 查询空房信息;
空房信息应该包括:【房型名称,空房数量,套餐名称,床型,早餐类型,套餐价格】
由于返回空房信息的数据类型比较复杂,所以我们一般会有一个DTO层或者VO层来负责装配这些数据。习惯原因,这里我直接用VO层了;老师是分成了DTO层,无大碍
@Data
@NoArgsConstructor
@AllArgsConstructor
public class VoFreeRoom {
private String roomTypeName;
private Integer freeCount;
private String solutionName;
private String bedType;
private String breakfastType;
private Double solutionPrice;
}
@RestController
@RequestMapping("/roomOrder")
public class RoomOrderController {
@Autowired
private RoomService roomService;
@GetMapping("/freeRooms")
public ResultJson freeRoom(String checkInDate, String checkOutDate){
try {
//调用Service,传入入住时间和退房时间取得空房信息
List<VoFreeRoom> voFreeRoomList = roomService.findFreeRoom(checkInDate,checkOutDate);
return new ResultJson("200","success",voFreeRoomList);
}catch (Exception e){
return new ResultJson("400","failed",null);
}
}
}
mapper层
在编写具体业务逻辑之前,先来把涉及到的sql准备好吧
注:我的解决方案只是其中的一种,有可能有缺陷,如果大家发现有问题还望能提醒我
思路:
- 首先向空方信息表中查询某个时间段中的房型的最小剩余量, 并将结果按照房间类型分组显示
对最小剩余量的说明:假设1号剩5间房,2号剩3间房;客户如果想要在1号和2号都入住的话,最多只能给其分配3间房。
对应的sql语句
- 查询所有的套餐信息
sql
- 查询所有套餐对应的房间类型信息
由于套餐表中存有房间类型ID的外键,这里有两种方式,一种使用连接,一种使用通过外键查询单条记录,各有优劣,这里我选用了后者
sql:
接下来就把这些SQL语句写进mapper层
注意,在mapper的xml文件里,特殊字符的表达: 大于号使用> 小于号使用<
空房信息mapper
@Mapper
public interface FreeRoomCalendarMapper {
List<FreeRoomCalendar> findFreeRooms(@Param("checkInDate") String checkInDate,@Param("checkOutDate")String checkOutDate);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.edu.fjzzit.web.myhotel.mapper.FreeRoomCalendarMapper">
<resultMap id="freeRoomCalendarMap" type="cn.edu.fjzzit.web.myhotel.model.FreeRoomCalendar">
<id column="free_room_calendar_id" jdbcType="INTEGER" property="freeRoomCalendarID" />
<result column="room_type_id" jdbcType="INTEGER" property="roomTypeID"/>
<result column="calendar_date" jdbcType="DATE" property="calendarDate"/>
<result column="total_count" jdbcType="INTEGER" property="totalCount"/>
<result column="free_count" jdbcType="INTEGER" property="freeCount"/>
<result column="MIN(free_count)" jdbcType="INTEGER" property="minFreeCount"/>
</resultMap>
<select id="findFreeRooms" resultMap="freeRoomCalendarMap">
SELECT room_type_id,MIN(free_count) as free_count
FROM free_room_calendar
WHERE calendar_date >= #{checkInDate}
AND calendar_date < #{checkOutDate}
GROUP BY room_type_id
</select>
</mapper>
房型Mapper,套餐Mapper:略
service层
最后就是业务层了
用户查询时候输入入住时间和退房时间,返回的是每种套餐的具体信息和剩余房间数量
思路:
- 查询所有套餐信息
- 通过入住日期和退房日期查询空房信息
- 遍历套餐信息,通过套餐信息中的房型ID外键查询房型信息
- 在每次遍历套餐信息的过程中,再对空房信息进行遍历,把房型ID相同的添加到VO层中
解释起来有点费劲,直接看代码吧!
RoomService
public interface RoomService {
List<VoFreeRoom> findFreeRoom(String checkInDate,String checkOutDate);
}
RoomServiceImpl
@Service
public class RoomServiceImpl implements RoomService {
@Autowired
private FreeRoomCalendarMapper freeRoomCalendarMapper;
@Autowired
private SolutionMapper solutionMapper;
@Autowired
private RoomTypeMapper roomTypeMapper;
@Override
public List<VoFreeRoom> findFreeRoom(String checkInDate, String checkOutDate) {
List<VoFreeRoom> voFreeRoomList = new ArrayList<>();
//查询所有的套餐
List<Solution> solutionList = solutionMapper.findAllSolutions();
//通过开始日期和结束日期先去空房日历表中查询最小空房数量
//操作mapper层
//从日历表中查询得到空房的房间类型和空房数量
List<FreeRoomCalendar> freeRoomCalendarList = freeRoomCalendarMapper.findFreeRooms(checkInDate,checkOutDate);
//遍历所有套餐
for(Solution solution:solutionList){
//遍历空房日历结果
for(FreeRoomCalendar freeRoomCalendar:freeRoomCalendarList){
//将符合套餐的房间类型装填进Vo层中
if(freeRoomCalendar.getRoomTypeID()==solution.getRoomTypeID()){
//取出根据套餐中的房型ID房型信息
RoomType roomType = roomTypeMapper.findFirstRoomTypeByID(solution.getRoomTypeID());
String roomTypeName = roomType.getRoomTypeName();
Integer freeCount = freeRoomCalendar.getFreeCount();
String solutionName = solution.getSolutionName();
String bedType = roomType.getBedType();
String breakfastType = solution.getBreakfastType();
Double solutionPrice = solution.getSolutionPrice();
voFreeRoomList.add(new VoFreeRoom(roomTypeName,freeCount,solutionName,bedType,breakfastType,solutionPrice));
}
}
//voFreeRoomList.add(new VoFreeRoom("",0,"","","",0.0));
}
return voFreeRoomList;
}
}
测试接口
尝试查询 2019-11-09 ~ 2019-11-11的空房信息