从orcal转到mysql中,总是被mysql中莫名的提交搞的数据混乱,因此记录一下各种情况。
首先先查看一下当前MYSQL数据库是否开启了自动提交。
在数据库命令行 show variables like ‘autocommit’;
mysql> show variables like ‘autocommit’;
±--------------±------+
| Variable_name | Value |
±--------------±------+
| autocommit | ON |
±--------------±------+
1 row in set (0.04 sec)
以上结果代表默认开启了自动提交操作。
想要在存储过程中有两种方式进行回滚和提交操作,第一种采用开启事物的方法,第二种是采用关闭自动提交的方法,指的是在存储过程中关闭,而不是整个数据库关闭。
以下操作是在数据库是自动提交的情况中实验的:采用的方法是第一种方法开启事物
准备工作两个存储过程分别是NewTest和NewTest1
一张数据表 test111,数据很简单如图所示,每个例子的初始情况都是这样。
单个存储过程
1.回滚
单纯的一个存储过程NewTest,如果想要进行回滚或者提交操作的时候需要开启事物,否则每执行一个更新或者删除操作都会被自动提交。
CREATE DEFINER=`root`@`%` PROCEDURE `NewTest`(
)
BEGIN
START TRANSACTION;/*开启事物*/
delete from test111 where id=1; #删除操作
rollback;#回滚
END;
结果:
2.提交
CREATE DEFINER=`root`@`%` PROCEDURE `NewTest`(
)
BEGIN
START TRANSACTION;/*开启事物*/
delete from test111 where id=1; #删除操作
commit;#提交
END
结果:
两个存储过程NewTest为父,NewTest1为子 也就是父调用子
1.两者都开启事物,并且两者都提交
CREATE DEFINER=`root`@`%` PROCEDURE `NewTest`(
)
BEGIN
START TRANSACTION;/*开启事物*/
delete from test111 where id=1; #删除操作
call NewTest1();
delete from test111 where id=3; #删除操作
commit;#提交
END
CREATE DEFINER=`root`@`%` PROCEDURE `NewTest1`(
)
BEGIN
START TRANSACTION;/*开启事物*/
delete from test111 where id=2;
commit;
END
结果:
2.两者都开启事物,父回滚,子提交
CREATE DEFINER=`root`@`%` PROCEDURE `NewTest`(
)
BEGIN
START TRANSACTION;/*开启事物*/
delete from test111 where id=1; #删除操作
call NewTest1();
delete from test111 where id=3; #删除操作
rollback;
END
CREATE DEFINER=`root`@`%` PROCEDURE `NewTest1`(
)
BEGIN
START TRANSACTION;/*开启事物*/
delete from test111 where id=2;
commit;
END
结果:
3.两者都开启事物,父回滚子回滚
CREATE DEFINER=`root`@`%` PROCEDURE `NewTest`(
)
BEGIN
START TRANSACTION;/*开启事物*/
delete from test111 where id=1; #删除操作
call NewTest1();
delete from test111 where id=3; #删除操作
rollback;#提交
END
结果:
4.两者都开启事物,父提交,子回滚
CREATE DEFINER=`root`@`%` PROCEDURE `NewTest`(
)
BEGIN
START TRANSACTION;/*开启事物*/
delete from test111 where id=1; #删除操作
call NewTest1();
delete from test111 where id=3; #删除操作
commit;#提交
END
CREATE DEFINER=`root`@`%` PROCEDURE `NewTest1`(
)
BEGIN
START TRANSACTION;/*开启事物*/
delete from test111 where id=2;
rollback;
END
结果:
从以上四个例子可以得出结论:在事物开启中,有且只能有一个事物能够被开启,当子存储过程开启了事物后,前面父亲的事物自动失效相当于没有开启过事物(也可以认为是第二个事物会将第一个事物给提交掉)。只要开启了事物之后,后面的代码都将会被事物所管辖。所以推荐,只让父亲开启事物,这样能够将子存储过程也包含到父存储过程的事物当中,实现多个存储过程回滚和提交的一致性。如果子存储过程既可当父亲,也可以当子存储过程,那么推荐用一个输入参数来判定,当前它是作为父亲还是作为子,作为父亲就开启事物并负责自己的提交和回滚,作为子就不开事物,接收父亲的管辖,提交和回滚操作都也都交于父亲来执行。重要的一点必须在离开存储过程之前需要有个提交或者是回滚的操作作为结束
以下操作是在数据库是自动提交的情况中实验的:采用的方法是第二种方法关闭自动提交
CREATE DEFINER=`root`@`%` PROCEDURE `NewTest`(
)
BEGIN
Set autocommit = 0;##关闭自动提交
update test111 set id=66 where id=12;
commit;#提交
update test111 set id=77 where id=13;
rollback;#回滚
update test111 set id=88 where id=14;
commit;#提交
END
关闭自动提交的方法比开启事物更加简洁,当存储过程关闭自动提交后,遇到commit将会提交,遇到rollback将会回滚。commit和rollback是互不干扰的,不具备包含关系,就如上图所示,commit之后到rollback之前的代码,才受rollback管辖。
与开启事物的方法一样,父存储过程可以掌控子存储过程(被调用的子存储过程就相当于一段写在父存储过程的代码,与其他父中的代码地位是相等的)。而且 Set autocommit = 0;作用范围不局限于begin-end之间,只要是 Set autocommit = 0之后的代码,都将会被其所管辖,最重要的一点一旦Set autocommit = 0,必须在离开存储过程之前需要有个提交或者是回滚的操作作为结束,否则没被提交和回滚的那段代码中操作过增删改的表将会被锁住。