2015-06-07 23 views
5

Zauważyłem, że START TRANSACTION automatycznie COMMIT poprzednie zapytania. Z tego powodu i faktu, że mam kilka procedur przechowywanych wywołanych przed końcem całej transakcji, muszę sprawdzić, czy jestem wewnątrz START TRANSACTION lub nie. Czytanie instrukcji Zrozumiałem, że autocommit jest ustawiony na false wewnątrz START TRANSACTION, ale nie wydaje się tak. Pisałem następującą procedurę:MySQL - Jak sprawdzić, czy START TRANSACTION jest aktywny

CREATE DEFINER=`root`@`localhost` PROCEDURE `test_transaction`() 
BEGIN 

show session variables like 'autocommit'; 

start transaction; 

show session variables like 'autocommit'; 

COMMIT; 

show session variables like 'autocommit'; 

END 

ale każdy show session variables like 'autocommit'; pokazu trybu automatycznego = ON, a ja spodziewałem się drugi AUTOCOMMIT = OFF.

Jak mogę sprawdzić, czy jestem w środku START TRANSACTION?

Muszę wykonać tę kontrolę, ponieważ mam procedurę 1, która wymaga START TRANSACTION, a następnie wywołuje procedurę2, która również potrzebuje START TRANSACTION. Ale załóżmy, że mam trzecią procedurę different_procedure, która również musi wywoływać procedure2, ale w tym przypadku different_procedure nie używa START TRANSACTION. W tym scenariuszu potrzebuję procedury2, aby sprawdzić, czy zainicjowano START TRANSACTION. Mam nadzieję, że to wystarczy.

Dzięki

Odpowiedz

1

Od https://dev.mysql.com/doc/refman/5.5/en/implicit-commit.html:

Transakcje nie mogą być zagnieżdżone. Jest to konsekwencja niejawnego zatwierdzenia wykonanego dla każdej bieżącej transakcji, gdy wydasz instrukcję START TRANSACTION lub jeden z jej synonimów.

Podejrzewam, że problem można rozwiązać, używając SET autocommit=0; zamiast START TRANSACTION;. Jeśli autocommit jest już 0, nie będzie to miało żadnego efektu.

Zobacz także Does setting autocommit=0 within a transaction do anything?

+0

Dzięki, że może być rozwiązaniem, ale jest brzydki. Uważam, że powinien istnieć czysty sposób sprawdzenia, czy znajdujesz się w "transakcji początkowej". –

+0

@Stefano Giacone Czy próbowałeś/aś SELECT @@ autocommit'? –

+0

Tak, to jest to samo. Autocommit SET = 0; rozwiązanie jest naprawdę okropne, wolę lepsze, jeśli to możliwe ... –

5

Można utworzyć funkcję, która będzie wykorzystywał błąd, który może wystąpić jedynie w ramach transakcji:

DELIMITER // 
CREATE FUNCTION `is_in_transaction`() RETURNS int(11) 
BEGIN 
    DECLARE oldIsolation TEXT DEFAULT @@TX_ISOLATION; 
    DECLARE EXIT HANDLER FOR 1568 BEGIN 
     -- error 1568 will only be thrown within a transaction 
     RETURN 1; 
    END; 
    -- will throw an error if we are within a transaction 
    SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; 
    -- no error was thrown - we are not within a transaction 
    SET TX_ISOLATION = oldIsolation; 
    RETURN 0; 
END// 
DELIMITER ; 

przetestować funkcję:

set @within_transaction := null; 
set @out_of_transaction := null; 

begin; 
    set @within_transaction := is_in_transaction(); 
commit; 

set @out_of_transaction := is_in_transaction(); 

select @within_transaction, @out_of_transaction; 

Wynik :

@within_transaction | @out_of_transaction 
--------------------|-------------------- 
        1 |     0 

Z MariaDB można użyć @@in_transaction