内容纲要
Redis+MySQL实现酒店预订功能
酒店预订从实际业务上分析是一个较复杂的功能实现,并不能是简单的增删查改。
涉及并发、一致性等问题。
技术选型:
- Redis
- MySQL
配置Redis
// 配置连接信息
略...
// 配置Redis序列化,不自己配置序列化可能会发生因序列化冲突而造成的错误
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
//string
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new StringRedisSerializer());
//Hash
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setDefaultSerializer(new GenericJackson2JsonRedisSerializer());
template.setStringSerializer(new StringRedisSerializer());
return template;
}
配置MySQL
//
// 略...
具体实现
public String userReserve(String userName, Integer hotelId, Integer roomId) {
String orderNum = UUID.randomUUID().toString();
if(StringUtils.isAnyBlank(userName)){
throw new BusinessException(BusinessErrorEnum.PARAMS_ERROR,"用户名不能为空");
}
// key-orderNum value-userName
if(hotelId == null || roomId == null){
throw new BusinessException(BusinessErrorEnum.PARAMS_ERROR,"酒店Id和房间ID不能为空");
}
redisTemplate.opsForValue().set(orderNum,userName);
redisTemplate.expire(orderNum,15, TimeUnit.MINUTES);
SqlSession sqlSession = getSqlSessionFactory().openSession(false);
Room room = null;
boolean success = false;
// SQL事务
try{
room = roomMapper.selectRoom(hotelId, roomId);
if (room==null){
throw new BusinessException(BusinessErrorEnum.SYSTEM_ERROR,"房间已被其他人预订,事务回滚");
}
boolean booked = roomMapper.setReserved(hotelId, roomId,userName, orderNum);
sqlSession.commit();
success = true;
}catch(BusinessException e){
// 事务回滚
sqlSession.rollback();
log.error("事务回滚----"+"预定失败,已被预订"+e.getMessage());
}finally {
sqlSession.close();
}
if(success){
// 预订成功
if(redisTemplate.hasKey(orderNum)){
// 用户还未取消
return room.toString();
}else {
// 用户已取消
roomMapper.cancelByOrderNum(orderNum);
throw new BusinessException(BusinessErrorEnum.NULL_ERROR,"用户已取消订单");
}
}else {
roomMapper.cancelByOrderNum(orderNum);
// 预订失败
if(redisTemplate.hasKey(orderNum)){
redisTemplate.expire(orderNum,0, TimeUnit.MINUTES);
throw new BusinessException(BusinessErrorEnum.SYSTEM_ERROR,"预订失败");
}else {
// 用户已取消
throw new BusinessException(BusinessErrorEnum.NULL_ERROR,"用户已取消订单");
}
}
}