1.創(chuàng)建表測試表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為主鍵,不能重復(fù)
2.創(chuàng)建存儲(chǔ)過程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.現(xiàn)象:執(zhí)行sp_test,由于id是唯一鍵,不能重復(fù),所以sp_test中執(zhí)行第二條insert語句時(shí),會(huì)出現(xiàn)錯(cuò)誤,后面的commit語句不會(huì)執(zhí)行,也就不會(huì)提交,再次執(zhí)行sp_test,報(bào)同樣的錯(cuò)誤,但觀察數(shù)據(jù)表,admin1卻已經(jīng)被寫到表里了
4.解釋:由于事務(wù)是針對當(dāng)前連接的,第一次執(zhí)行sp_test時(shí),start transaction;開始了一個(gè)新的事物,第一個(gè)insert正確執(zhí)行,第二個(gè)insert報(bào)錯(cuò),存儲(chǔ)過程返回,commit沒有執(zhí)行;第二次執(zhí)行sp_test,start transaction暗含了結(jié)束該連接的上一個(gè)事務(wù)的語義,由于第一次執(zhí)行時(shí)admin1被正確寫入,此時(shí)提交,admin1就被真正的寫到表里了。
5.方案:第一種方案,把事物的開始,提交,回滾封裝到程序里面,只在存儲(chǔ)過程里面做具體的插入,更新操作,如果存儲(chǔ)過程成功就提交,如果失敗就回滾;第二種方案,在存儲(chǔ)過程里面捕獲異常,如果出現(xiàn)異常就回滾,否則就提交,具體代碼為:
---------------------------------------------------------------------
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
---------------------------------------------------------------------
這種方式,程序里面不會(huì)捕捉到任何異常,因?yàn)樵诖鎯?chǔ)過程里處理了,如果存儲(chǔ)過程返回0表示成功,返回-1表示失敗,如有必要也可以返回自增id