1.創建表測試表tb_test,如下:
--------------------------------------------------------------------
CREATE TABLE `tb_test` (
`id` int(32) NOT NULL COMMENT 'k',
`name` varchar(32) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--------------------------------------------------------------------
其中id為主鍵,不能重復
2.創建存儲過程sp_test,如下:
-------------------------------------------------------------------
begin
start transaction;
insert into tb_test(id,name) values (10000,'admin1');
insert into tb_test(id,name) values (10000,'admin2');
commit;
end
---------------------------------------------------------------------
3.現象:執行sp_test,由于id是唯一鍵,不能重復,所以sp_test中執行第二條insert語句時,會出現錯誤,后面的commit語句不會執行,也就不會提交,再次執行sp_test,報同樣的錯誤,但觀察數據表,admin1卻已經被寫到表里了
4.解釋:由于事務是針對當前連接的,第一次執行sp_test時,start transaction;開始了一個新的事物,第一個insert正確執行,第二個insert報錯,存儲過程返回,commit沒有執行;第二次執行sp_test,start transaction暗含了結束該連接的上一個事務的語義,由于第一次執行時admin1被正確寫入,此時提交,admin1就被真正的寫到表里了。
5.方案:第一種方案,把事物的開始,提交,回滾封裝到程序里面,只在存儲過程里面做具體的插入,更新操作,如果存儲過程成功就提交,如果失敗就回滾;第二種方案,在存儲過程里面捕獲異常,如果出現異常就回滾,否則就提交,具體代碼為:
---------------------------------------------------------------------
begin
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
begin
rollback;
select -1;
end;
start transaction;
insert into tb_test(id,name) values (10000,'admin1');
insert into tb_test(id,name) values (10000,'admin2');
commit;
select 0;
end
---------------------------------------------------------------------
這種方式,程序里面不會捕捉到任何異常,因為在存儲過程里處理了,如果存儲過程返回0表示成功,返回-1表示失敗,如有必要也可以返回自增id