wiki:Transactions

Version 41 (modified by 222039, 3 weeks ago) ( diff )

--

Трансакции

Вовед

Во рамките на оваа фаза, целта е да се прикаже како еден ваков систем за авионски резервации управува со паралелни барања од повеќе корисници во исто време, без да се наруши конзистентноста на податоците и практики за истото во еден MySQL сервер.

Фокусот е на тоа системот да гарантира конзистентна продажба и резервација на седишта односно да не може да се случи две различни резервации да завршат со исто седиште на ист лет, и да нема ситуација на overbooking (повеќе резервирани места од капацитетот на авионот).

Покрај тоа, анализираме како системот треба правилно да се однесува при паралелни промени врз исти податоци, како на пример:

  • промена на седиште
  • откажување резервација
  • промени во распоредот на летот.

Овие операции во пракса често се случуваат истовремено од различни корисници и без трансакции и locking можат да доведат до неконзистентни резултати, „изгубени” промени или некоректен број на резервации.

Core transactional domain во airportdb

booking – централната табела за резервации. Токму тука најчесто се појавуваат concurrency проблеми , бидејќи повеќе корисници можат истовремено да направат booking (или менуваат) на седишта за ист лет.

No image "booking table image" attached to Transactions

flight - табела што го дефинира летот (од каде до каде, време на поаѓање и пристигнување, авиокомпанија и кој авион го извршува летот). Оваа табела е важна затоа што секоја резервација се врзува за конкретен лет, а промени во летот (на пример reschedule или промена на авион) имаат директно влијание врз валидноста на постоечките резервации.

No image "flight table image" attached to Transactions

airplane - табела која го носи најважниот капацитетен параметар: capacity. Ова е основата за контролирање на overbooking. Дури и кога различни седишта се резервираат паралелно, системот мора да осигури дека вкупниот број резервации за летот не го надминува капацитетот на авионот кој го извршува летот.

No image "airplane table image" attached to Transactions

Дополнително, постојат и поддржувачки табли кои се важни за реалистичност и traceability:

  • passenger и passengerdetails – иако не се директниот извор на concurrency проблемите, тие често учествуваат во транзакции (на пример при креирање нов патник + резервација во една атомска операција).
  • flight_log – корисна за audit (логирање на историја кој и кога направил промена). Во реални системи audit логиката е критична, особено при debugging на проблеми со конкурентност и при следење на промени во распоредите или атрибутите на летовите.

Дефинирани правила за конзистентност во airportdb

Овие правила ја опишуваат „точната“ состојба на системот и служат како основа за дизајн на транзакции, заклучувања и ограничувања во базата.

1) Единственост на седиште по лет
2) Почитување на капацитетот (без overbooking)
3) Атомичност на промени (seat change / cancel)
4) Reschedule без нарушување на капацитет

ALTER TABLE booking
ADD CONSTRAINT uq_booking_flight_seat UNIQUE (flight_id, seat);

ALTER TABLE booking
ADD INDEX ix_booking_flight (flight_id);

ALTER TABLE flight
ADD INDEX ix_flight_airplane (airplane_id);

ALTER TABLE airplane
ADD INDEX ix_airplane_id_capacity (airplane_id, capacity);

UNIQUE (flight_id, seat) e најчист race-condition stopper за кога двајца купуваат исто седиште, ама во реален систем имаме и перформанси и lock behavior. Во concurrency сценарија (многу паралелни резервации), сакаме:

  • критичните проверки да бидат брзи (да не држат locks предолго),
  • да избегнеме full table scans што прават повеќе блокирања и оптоварување

Затоа додадовме и индекси на колоните што најчесто се користат во транзакциските операции.

Реални сценарија

Сценарио 1

Нашата база е дел од апликација за онлајн резервации. Во peak часови (петок вечер), стотици корисници паралелно купуваат седишта за ист лет.

  1. Корисник1 и Корисник2 во ист момент резервираат седиште 12A” на истиот лет.

Без трансакции/ограничувања, може и двата корисници да добијат потвра => overbooking.

  1. Корисник1 потоа сака да се премести од 12A на 14C. Во истиот момент, друг корисник се обидува да го земе 14C.

Ако промената не е атомична: старото седиште ослободено, новото неуспешно, или дупликат.

  1. Паралелно, оператор од авиокомпанијата прави reschedule: го менува авионот за летот со помал капацитет (поради технички проблем).

Ако системот дозволи промена без да провери колку резервации веќе постојат, може да создаде лет каде bookings > capacity. Ова мора да се блокира или одбие.

Затоа овие проблеми во процедурите ги решаваме со трансакции така што:

  • ги заклучуваме релевантните редови додека трае проверката,
  • се осигуруваме дека операцијата е атомична (COMMIT или ROLLBACK),

Procedure Reserve Seat (спречува overbooking + double seat)

Затоа што имаме “check-then-write” логика: прво проверуваме капацитет/број резервации, па insert. Без транзакција, две сесии можат да поминат проверки паралелно и да го надминат капацитетот.

DELIMITER $$

CREATE PROCEDURE sp_reserve_seat(
  IN p_flight_id INT,
  IN p_seat CHAR(4),
  IN p_passenger_id INT,
  IN p_price DECIMAL(10,2)
)
BEGIN
  DECLARE v_capacity INT;
  DECLARE v_booked INT;
  DECLARE exit handler FOR SQLEXCEPTION
  BEGIN
    ROLLBACK;
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Reservation failed (transaction rolled back).';
  END;

  START TRANSACTION;

  SELECT a.capacity INTO v_capacity
  FROM flight f
  JOIN airplane a ON a.airplane_id = f.airplane_id
  WHERE f.flight_id = p_flight_id
  FOR UPDATE;

  SELECT COUNT(*) INTO v_booked
  FROM booking
  WHERE flight_id = p_flight_id
  FOR UPDATE;

  IF v_booked >= v_capacity THEN
    ROLLBACK;
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Flight is full (capacity exceeded).';
  END IF;

  INSERT INTO booking (flight_id, seat, passenger_id, price)
  VALUES (p_flight_id, p_seat, p_passenger_id, p_price);

  COMMIT;
END$$

DELIMITER ;

Attachments (3)

Download all attachments as: .zip

Note: See TracWiki for help on using the wiki.