4

我目前正在阅读很多有关 InnoDB 中事务的信息,此时我只使用过 myISAM 表,所以我不太习惯这一切:

这是我的表格方案:

CREATE TABLE IF NOT EXISTS `reservations` (
  `id_reservation` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
  `id_room` mediumint(8) unsigned NOT NULL,
  `date_from` date NOT NULL,
  `date_to` date NOT NULL,
  `cancelled` enum('Y','N') NOT NULL DEFAULT 'N',
  PRIMARY KEY (`id_reservation`),
  KEY `id_room` (`id_appartement`)
) ENGINE=InnoDB;

现在假设我想为房间 ID 15 插入一个新的预订,从 2012 年 2 月 15 日到 2012 年 2 月 24 日,这是我认为根据我阅读的内容我应该做的事情:

  1. 开始交易:

    START TRANSACTION;
    
  2. 插入行

    INSERT INTO reservations SET 
      id_room = 15, 
      date_from = '2012-02-15', 
      date_to='2012-02-24', 
      cancelled='N';
    
  3. 检查是否有与我刚刚进行的预订相冲突的预订

    SELECT * FROM reservations WHERE 
      id_room = 15 
      AND cancelled = 'N' 
      AND date_from < '2012-02-24' AND date_to > '2012-02-15' 
      AND id_reservation <> LAST_INSERT_ID();
    
  4. 如果不,COMMIT;

  5. 别的,ROLLBACK;

问题是,在默认隔离模式(REPEATABLE-READ)下,一旦我开始事务,我将看不到在这个事务之外进行的任何其他 INSERT。那么,如果在步骤 1)之后,另一个用户插入了一个冲突的预订,会发生什么?

也许我应该在这种情况下使用 READ-COMMITED ?但这不会导致问题吗?感谢您的帮助!

4

2 回答 2

5

你所拥有的很好,但是你需要在你的事务中添加一个表和一个查询。

该表需要每一行id_room。你可能已经有了那张桌子。

因此,在 START TRANSACTION 之后立即执行以下操作:

SELECT * FROM room WHERE id_room=15 FOR UPDATE;

这将阻止下一个尝试预订同一个房间的人,直到您提交或回滚您的事务,只要下一个人也使用此 FOR UPDATE 语法。

http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html

于 2012-09-05T20:53:59.857 回答
0

因此,假设我使用 php 脚本访问我的数据库,使用 PDO 和事务为您预订房间一段时间的预订系统。时段为 30 分钟,但房间将被预订至少一小时。因此,一旦预订了之前的时间段,它也将被禁用,因为只能预订 30 分钟。假设两个或更多客户尝试访问并预订某个时间段或之前的一个时间段,第一个会成功而其他人将被拒绝,这意味着脚本将结束,或者他们会在第一个完成后等待,如果他确实预订了当他们再次尝试或在他决定不预订房间的情况下,他们将被拒绝,第二个将选择并经历相同的事件序列

于 2012-11-25T08:56:13.150 回答