1. 程式人生 > >MySQL儲存過程 事務transaction

MySQL儲存過程 事務transaction

Mysql中,單個Store Procedure(SP)不是原子操作,而oracle則是原子的。如下的儲存過程,即使語句2失敗,語句1仍然會被commit到資料庫中:

create table testproc(id int(4) primary key, name varchar(100));
 
CREATE PROCEDURE test_proc_ins(
IN i_id INT,
IN i_name VARCHAR(100)
)
BEGIN
           INSERT INTO testproc VALUES (i_id, i_name);  -- 語句1
           INSERT INTO testproc VALUES (i_id, i_name);  -- 語句2(因為id為PK,此語句將出錯)。
END;

要使整個儲存過程成為一個原子操作的辦法是:在儲存過程主體開始部分,指定開始一個事務。語句2失敗,語句1不會被commit到資料庫中,儲存過程將會在呼叫時丟擲一個異常。
CREATE PROCEDURE test_proc_ins(
IN i_id INT,
IN i_name VARCHAR(100)
)
BEGIN
start transaction; --整個儲存過程指定為一個事務
           INSERT INTO testproc VALUES (i_id, i_name);
           INSERT INTO testproc VALUES (i_id+1, i_name); -- 這裡把id+1,避免主鍵衝突
commit; -- 語句1。必須主動提交
END;

CREATE PROCEDURE test_proc_ins(
IN i_id INT,
IN i_name VARCHAR(100),
OUT o_ret INT)
BEGIN
start transaction;
           INSERT INTO testproc VALUES (i_id, i_name);
           INSERT INTO testproc VALUES (i_id+1,i_name);
           commit; -- 語句1,提交後,事務已結束
           set o_ret = 1;
           start transaction; -- 再啟一個事務
           INSERT INTO testproc VALUES (i_id+2,i_name); -- 語句2
           INSERT INTO testproc VALUES (i_id+2,i_name); -- 語句3
           set o_ret = 2;
           commit; -- 資料正常的情況下,需要再次commit以結束事務
END;


MySQL的回滾事物的操作

在處理事務時,使用SQLException捕獲SQL錯誤,然後處理; 按照這個推論,我們必須在MySQL儲存過程中捕獲SQL錯誤,最後判斷是回滾(ROLLBACK)還是提交(COMMIT)

DROP PROCEDURE IF EXISTS  test_sp1 
CREATE PROCEDURE test_sp1( )  
    BEGIN  
    DECLARE t_error INTEGER DEFAULT 0;  
    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET t_error=1;  
  
        START TRANSACTION;  
            INSERT INTO test VALUES(NULL, 'test sql 001');     
            INSERT INTO test VALUES('1', 'test sql 002');     
  
        IF t_error = 1 THEN  
            ROLLBACK;  
        ELSE  
            COMMIT;  
        END IF;  
   select t_error;   //返回標識位的結果集;
END