实现用户预订座位时可用座位数自动减1的Java+MySQL方案咨询
实现预订座位自动扣减的解决方案
你不需要用数组实现该功能,数组属于内存临时存储,服务重启后数据会重置,多用户并发访问时也会出现数据不一致的问题,直接通过数据库事务操作就能可靠实现需求。
核心实现逻辑
- 先查询对应车次的当前可用座位数,校验是否大于0
- 开启数据库事务,同时执行两个操作:插入预订记录、将对应车次可用座位数减1
- 两个操作都成功则提交事务,任意一个失败就回滚,避免数据不一致
- 操作完成后刷新页面/组件上的可用座位展示值
修改后的代码示例
try { String route_number = rnB.getText(); String depature_on = doB.getText(); String depature_time = dtB.getText(); Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/eurobusdb?useSSL=false","root","Abc123"); // 关闭自动提交,开启事务 connection.setAutoCommit(false); // 第一步:先查询当前车次的可用座位数,校验可预订性 String QUERY_SEATS_SQL = "SELECT available_seats FROM bus_schedule WHERE route = ? AND depature_on = ? AND depature_time = ? FOR UPDATE"; PreparedStatement queryPs = connection.prepareStatement(QUERY_SEATS_SQL); queryPs.setString(1, route_number); queryPs.setString(2, depature_on); queryPs.setString(3, depature_time); ResultSet rs = queryPs.executeQuery(); int availableSeats = 0; if(rs.next()){ availableSeats = rs.getInt("available_seats"); } if(availableSeats <= 0){ throw new Exception("当前车次已无可用座位,预订失败"); } // 第二步:插入预订记录 String SQL_INSERT_BOOKING = "INSERT INTO booking (Depature_Country_And_City , Destination_Country_And_City, Depature_On, Depature_Time, Estimated_Time_Taken, Available_Seats, Price, Status, route, name, contact_number) VALUES ( ?,?,?,?,?,?,?,?,?,?,?);"; PreparedStatement insertPs = connection.prepareStatement(SQL_INSERT_BOOKING); insertPs.setString(1, String.valueOf(combo1.getSelectedItem())); insertPs.setString(2, String.valueOf(combo2.getSelectedItem())); insertPs.setString(3, depature_on); insertPs.setString(4, depature_time); insertPs.setString(5, timeB.getText()); // 这里存预订时的剩余座位数,扣减前的数或者扣减后的可根据业务需求调整 insertPs.setString(6, String.valueOf(availableSeats - 1)); insertPs.setString(7, pB.getText()); insertPs.setString(8, "Booked"); insertPs.setString(9, route_number); insertPs.setString(10, name.getText()); insertPs.setString(11, contact.getText()); insertPs.executeUpdate(); // 第三步:更新车次可用座位数,扣减1 String UPDATE_SEATS_SQL = "UPDATE bus_schedule SET available_seats = available_seats - 1 WHERE route = ? AND depature_on = ? AND depature_time = ?"; PreparedStatement updatePs = connection.prepareStatement(UPDATE_SEATS_SQL); updatePs.setString(1, route_number); updatePs.setString(2, depature_on); updatePs.setString(3, depature_time); updatePs.executeUpdate(); // 提交事务 connection.commit(); // 刷新页面上的可用座位展示 asb.setText(String.valueOf(availableSeats - 1)); } catch (Exception e) { // 出现异常回滚事务 if(connection != null){ try { connection.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } e.printStackTrace(); // 这里可以加弹窗提示用户预订失败的原因 } finally { // 关闭连接等资源 if(connection != null){ try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } }
注意事项
- 你需要提前在数据库中创建车次调度表
bus_schedule,字段至少包含route(车次号)、depature_on(发车日期)、depature_time(发车时间)、available_seats(可用座位数),初始化时对应车次的available_seats设为35即可 - 查询可用座位时加
FOR UPDATE是为了加行锁,避免并发预订时出现超卖问题 - 原代码中你直接调用组件的
toString()方法是错误的,应该调用getText()方法获取输入的内容
内容的提问来源于stack exchange,提问作者Vimesh Perera
相关产品推荐
相关产品推荐

