MySQL技术内幕 InnoDB存储引擎 344页.
原来看过这段,总而言之,就是MySQL不要在存储过程中控制事务.
当时没有仔细看细节,只是记住了一个结论.
毕竟都21世纪了.还有用存储过程的?
但是..#(×&%¥×&@……&……#@&
以如下过程为例.
-
drop table nums;
-
drop procedure pCreateNums;
-
-
create table nums(id int not null primary key);
-
-
delimiter $$
-
create procedure pCreateNums(cnt int)
-
begin
-
-
start transaction;
-
insert into nums(id) values(cnt+rand()*100);
-
insert into nums(id) values(cnt);
-
commit;
-
end $$
-
delimiter ;
-
-
call pCreateNums(10);
-
call pCreateNums(10);
连续调用两次过程,会触发主键冲突的异常.
最后的commit没有执行,第二个过程的事务并未完成.

这时,需要上层调用的程序,进行事务的提交或者回滚.
当然,也可以定义一个Handler进行异常处理.
-
drop table nums;
-
drop procedure pCreateNums;
-
-
create table nums(id int not null primary key);
-
-
delimiter $$
-
create procedure pCreateNums(cnt int)
-
begin
-
declare exit handler for sqlexception rollback;
-
start transaction;
-
insert into nums(id) values(cnt+rand()*100);
-
insert into nums(id) values(cnt);
-
commit;
-
end $$
-
delimiter ;
-
-
call pCreateNums(10);
-
call pCreateNums(10);

第一个过程执行成功,第二个过程触发异常处理自动回滚
但是,上层的JAVA程序对于这一切,都透明了..
他后续的工作怎么处理?
缓存是否更新?分布式架构下,任务还继续吗?给客户端返回什么?
所以,过程和JAVA程序还得约定异常的类型.
-
drop table nums;
-
drop procedure pCreateNums;
-
-
create table nums(id int not null primary key);
-
-
delimiter $$
-
create procedure pCreateNums(cnt int)
-
begin
-
declare exit handler for sqlexception begin rollback;select -1;end;
-
start transaction;
-
insert into nums(id) values(cnt+rand()*100);
-
insert into nums(id) values(cnt);
-
commit;
-
select 1;
-
end $$
-
delimiter ;

这样约定异常的常量,把异常处理,自己又实现了一遍.
MSSQL 可以自动回滚事务,并且会抛出异常,上层JAVA开发可以捕获这个异常.
但是MySQL还是做不到的.
所以事务控制最好由程序端完成.
-
drop table nums;
-
drop procedure pCreateNums;
-
-
create table nums(id int not null primary key);
-
-
delimiter $$
-
create procedure pCreateNums(cnt int)
-
begin
-
start transaction;
-
insert into nums(id) values(cnt+rand()*100);
-
insert into nums(id) values(cnt);
-
end $$
-
delimiter ;
JAVA程序调用过程之前,开启事务,然后调用过程,根据过程的执行情况,提交或者回滚.
不要在存储过程中控制事务
原文:http://blog.itpub.net/29254281/viewspace-2112572/