如何利用MySQL和Java开发一个简单的在线旅游预订系统

来源:草根站长作者:广州SEO公司头衔:草根站长
导读:本期聚焦于小伙伴创作的《如何利用MySQL和Java开发一个简单的在线旅游预订系统》,敬请观看详情。设想你接手了一个周末短途游产品的孵化项目,最棘手的是怎样用最少成本把用户下单、库存扣减和订单查询跑通。本文从库表建模出发,给出旅客表、线路表、订单表的E-R关系,并用Spring Boot配合MyBatis实现预订接口。重点说明并发下单时如何利用数据库唯一索引与事务隔离避免超卖,以及通过连接池提升吞吐。顺着这套实现,你能快速搭出一个可演示的旅游预订后台,之后再补足支付与退改规则。

在线旅游预订系统的核心是把旅游资源(线路、库存)与用户订单通过关系型数据库可靠地关联起来,并用Java服务端处理业务逻辑。下面以MySQL为存储、Java为开发语言,逐步实现一个支持线路浏览、下单与订单查询的最小可用系统。

如何利用MySQL和Java开发一个简单的在线旅游预订系统

一、数据库设计

在MySQL中,我们需要三张核心表:旅客表、旅游线路表、订单表。旅客表记录用户基本信息;线路表保存旅游产品名称、价格、库存;订单表关联旅客与线路,并标记订单状态。合理的索引能显著提升查询效率。

下面给出建表语句,其中线路表的stock字段表示剩余库存,订单表对user_idroute_id建立联合唯一索引,防止同一用户重复创建未支付订单造成数据混乱。

CREATE TABLE traveler (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(50) NOT NULL,
  phone VARCHAR(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE travel_route (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  title VARCHAR(100) NOT NULL,
  price DECIMAL(10,2) NOT NULL,
  stock INT NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE booking_order (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  user_id BIGINT NOT NULL,
  route_id BIGINT NOT NULL,
  status TINYINT NOT NULL DEFAULT 0,
  create_time DATETIME NOT NULL,
  UNIQUE KEY uk_user_route (user_id, route_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

二、Java项目结构

采用Spring Boot加MyBatis的组合可以降低配置成本。控制器层接收HTTP请求,服务层编写预订逻辑,持久层通过Mapper操作MySQL。这种分层让代码职责清晰,也方便后续单元测试。

pom.xml中引入必要依赖后,我们通过注解方式编写Mapper。下面的接口定义了扣减库存与插入订单两个方法,二者将在同一个事务中调用,保证一致性。

@Mapper
public interface BookingMapper {
    @Update("UPDATE travel_route SET stock = stock - 1 WHERE id = #{routeId} AND stock > 0")
    int decreaseStock(@Param("routeId") Long routeId);

    @Insert("INSERT INTO booking_order(user_id, route_id, status, create_time) " +
            "VALUES(#{userId}, #{routeId}, 0, NOW())")
    int insertOrder(@Param("userId") Long userId, @Param("routeId") Long routeId);
}

三、预订业务逻辑实现

下单时要先扣库存再写订单。由于SQL中stock > 0的条件限制,若库存不足则更新行数为0,此时应回滚并提示售罄。利用Spring的@Transactional注解,可确保扣减与插入要么都成功要么都失败。

以下服务方法演示了完整流程:先调用decreaseStock,返回影响行数为0时直接抛异常;否则插入订单。这样即使高并发请求同时进来,数据库行锁也会串行化库存修改,避免超卖。

@Service
public class BookingService {
    @Autowired
    private BookingMapper bookingMapper;

    @Transactional(rollbackFor = Exception.class)
    public void book(Long userId, Long routeId) {
        int updated = bookingMapper.decreaseStock(routeId);
        if (updated == 0) {
            throw new RuntimeException("库存不足或线路不存在");
        }
        bookingMapper.insertOrder(userId, routeId);
    }
}

四、接口暴露与连接池配置

最后用REST控制器把预订能力开放给前端。同时,在配置文件中设置HikariCP连接池,避免每次请求都新建物理连接。合理的池大小通常接近数据库最大连接数的三分之二。

下面代码展示了一个简化的下单接口,实际项目中还应加入参数校验、登录态校验与全局异常处理。通过Postman或简单页面即可完成预订验证。

@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    private BookingService bookingService;

    @PostMapping("/book")
    public String book(@RequestParam Long userId, @RequestParam Long routeId) {
        bookingService.book(userId, routeId);
        return "预订成功";
    }
}

五、总结与扩展

上述方案用MySQL事务与唯一索引解决了旅游预订中的超卖与重复下单问题,Java侧通过分层架构保持代码可维护。对于演示或小规模应用已经足够。

若日后用户量增长,可引入Redis缓存线路信息、用消息队列异步处理订单状态流转,并将库存扣减改为预扣模式。但无论怎么演进,本文的库表关系与事务边界都是系统稳定运行的基石。

MySQLJava旅游预订系统修改时间:2026-08-01 05:18:11

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。