Mysql
 sql >> Baza danych >  >> RDS >> Mysql

mysql - tworzenie mechanizmu podobnego do sekwencji Oracle

Poniżej znajduje się prosty przykład z FOR UPDATE blokada intencji . Zamek na poziomie rzędu z silnikiem INNODB. Przykład pokazuje cztery wiersze dla następnych dostępnych sekwencji, które nie ucierpią z powodu dobrze znanej anomalii przerw INNODB (przypadek, w którym przerwy występują po nieudanym użyciu AUTO_INCREMENT).

Schemat:

-- drop table if exists sequences;
create table sequences
(   id int auto_increment primary key,
    sectionType varchar(200) not null,
    nextSequence int not null,
    unique key(sectionType)
) ENGINE=InnoDB;

-- truncate table sequences;
insert sequences (sectionType,nextSequence) values
('Chassis',1),('Engine Block',1),('Brakes',1),('Carburetor',1);

Przykładowy kod:

START TRANSACTION; -- Line1
SELECT nextSequence into @mine_to_use from sequences where sectionType='Carburetor' FOR UPDATE; -- Line2 
select @mine_to_use; -- Line3
UPDATE sequences set nextSequence=nextSequence+1 where sectionType='Carburetor'; -- Line4
COMMIT; -- Line5

Idealnie nie masz Line3 lub w ogóle bloaty kod, który opóźniłby innych klientów na Lock Wait. Oznacza to, że pobierz następną sekwencję do użycia, wykonaj aktualizację (część zwiększająca się) i COMMIT , jak najszybciej .

Powyższe w procedurze składowanej:

DROP PROCEDURE if exists getNextSequence;
DELIMITER $$
CREATE PROCEDURE getNextSequence(p_sectionType varchar(200),OUT p_YoursToUse int)
BEGIN
    -- for flexibility, return the sequence number as both an OUT parameter and a single row resultset
    START TRANSACTION;
    SELECT nextSequence into @mine_to_use from sequences where sectionType=p_sectionType FOR UPDATE;
    UPDATE sequences set nextSequence=nextSequence+1 where sectionType=p_sectionType;
    COMMIT; -- get it and release INTENTION LOCK ASAP
    set [email protected]_to_use; -- set the OUT parameter
    select @mine_to_use as yourSeqNum; -- also return as a 1 column, 1 row resultset
END$$
DELIMITER ;

Test:

set @myNum:= -1;
call getNextSequence('Carburetor',@myNum);
+------------+
| yourSeqNum |
+------------+
|          4 |
+------------+
select @myNum; -- 4

Zmodyfikuj procedurę składowaną zgodnie z potrzebami, na przykład mając tylko 1 z 2 mechanizmów pobierania numeru sekwencji (parametr OUT lub zestaw wyników). Innymi słowy, łatwo jest porzucić OUT koncepcja parametrów.

Jeśli nie zastosujesz się do zwolnienia LOCK jak najszybciej (co oczywiście nie jest potrzebne po aktualizacji) i przystąpisz do wykonywania czasochłonnego kodu przed wydaniem, po upływie limitu czasu dla innych klientów oczekujących na sekwencję mogą wystąpić następujące zdarzenia numer:

BŁĄD 1205 (HY000):Przekroczono limit czasu oczekiwania na blokadę; spróbuj ponownie uruchomić transakcję

Mam nadzieję, że to nigdy nie stanowi problemu.

show variables where variable_name='innodb_lock_wait_timeout';

Strona podręcznika MySQL dla innodb_lock_wait_timeout .

W moim systemie w tej chwili ma wartość 50 (sekund). Oczekiwanie dłużej niż sekundę lub dwie jest prawdopodobnie nie do zniesienia w większości sytuacji.

Interesująca podczas TRANSAKCJI jest również ta sekcja danych wyjściowych następującego polecenia:

SHOW ENGINE INNODB STATUS;



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Wydajność wkładania wsadowego JDBC

  2. Użyj powiązanego parametru wiele razy

  3. Jak uniknąć dzielenia przez zero w MySQL

  4. Zresetuj hasło root serwera MySQL

  5. Jak działa funkcja OCT() w MySQL