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