MySQL儲存過程 事務transaction
阿新 • • 發佈:2019-02-15
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