php设置mysql事务级别_php操作mysql事务深度测试

一 事务是什么?

正常的sql语句是一条一条的执行,各个sql之间互不影响。

事务的机制类似于一个黑盒,黑盒里的sql语句(多条)要么全部成功了,要么全部失败了。(土话就这么讲,术语我就不说了)

二 如何应用事务?

一个事务有三个关键步骤:开始、提交、回滚。

开始就是要告诉数据库我要开始事务了,那么数据库就会给你提供一个黑盒,接下来你就开始执行sql,如果sql都没问题,那么就执行提交,那么黑盒里操作的结果就会真正写入数据库,如果有失败的,那么执行以下回滚,数据库没有任何改变。

从这个角度看,黑盒更像是一个“沙盒”。

php想对应的是操作mysqli库的三个方法:  mysqli::autocommit,  mysqli::commit(),  mysqli::rollback().

三 单元测试

1.创建mysql测试表(MyISAM引擎不支持事务,InnoDB引擎可以支持,所以将测试表建为InnoDB引擎)

表名:transaction_test,两个字段:id主键自增,content字符串类型。

CREATE TABLE`transaction_test`(

`id`int(11) NOT NULLAUTO_INCREMENT,

`content`varchar(256) DEFAULT NULL,PRIMARY KEY(`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='php事务测试表';

2.插入初始化数据

insert into transaction_test(content) values('北京'),('上海'),('广州');

如图:

650fdef4a49ea663c70bf0018377a79d.png

3.php连接数据库并插入数据测试

创建transaction_test.php

69c5a8ac3fa60e0848d784a6dd461da6.png

if (mysqli_connect_errno()) {printf("Connect failed: %s\n", mysqli_connect_error());exit();

}/*set charset*/

$sql_set_charset = "set names utf8";$query = $mysqli->query($sql_set_charset);if($query===false) {echo 'set charset failed
';exit(0);

}/*insert*/

$sql_1 = "insert into transaction_test(`content`) values('天津')";$query1 = $mysqli->query($sql_1);if($query1===false) {echo 'query1 failed
';

}else{printf("insert_id one: %d
", $mysqli->insert_id);

}$mysqli->close();?>

69c5a8ac3fa60e0848d784a6dd461da6.png

运行效果及数据库结果:

e8dbf6eb2c82b47cc283af5604d5c770.png      

96f9910ae637a01ee607efea2b4abd6f.png

插入OK。

4.测试mysqli::autocommit()。

autocommit()方法是设置数据库是否自动提交,参数为true和false,默认true。默认状态下每执行一次query(),数据库就会提交一次,那么如果设置为false,数据库就不会自动提交,那么就可以开始事务了,具体用法看下面的测试:

在上面代码的基础上,在插入数据的sql语句query之前,关闭自动提交。

69c5a8ac3fa60e0848d784a6dd461da6.png

if (mysqli_connect_errno()) {printf("Connect failed: %s\n", mysqli_connect_error());exit();

}/*set charset*/

$sql_set_charset = "set names utf8";$query = $mysqli->query($sql_set_charset);if($query===false) {echo 'set charset failed
';exit(0);

}/*关闭自动提交,开始事务*/

$mysqli->autocommit(false);/*insert*/

$sql_1 = "insert into transaction_test(`content`) values('重庆')";$query1 = $mysqli->query($sql_1);if($query1===false) {echo 'query1 failed
';

}else{printf("insert_id one: %d
", $mysqli->insert_id);

}$mysqli->close();?>

69c5a8ac3fa60e0848d784a6dd461da6.png

运行效果及数据库结果:

5f4ca105e3f4586c74c9e9069968e046.png    

09332f7de11fd97e20f2d921ce3435cc.png

分析:php返回id为5,但数据库却没有这条记录,说明开始事务之后所执行的query只是在一个“沙盒”里,并没有真正的写入到数据库。

5.测试mysqli::commit()

在上面代码中插入代码的后面加上commit()方法。

69c5a8ac3fa60e0848d784a6dd461da6.png

if (mysqli_connect_errno()) {printf("Connect failed: %s\n", mysqli_connect_error());exit();

}/*set charset*/

$sql_set_charset = "set names utf8";$query = $mysqli->query($sql_set_charset);if($query===false) {echo 'set charset failed
';exit(0);

}/*关闭自动提交,开始事务*/

$mysqli->autocommit(false);/*insert*/

$sql_1 = "insert into transaction_test(`content`) values('哈尔滨')";$query1 = $mysqli->query($sql_1);if($query1===false) {echo 'query1 failed
';

}else{printf("insert_id one: %d
", $mysqli->insert_id);

}/*事务提交*/

$mysqli->commit();$mysqli->close();?>

69c5a8ac3fa60e0848d784a6dd461da6.png

运行效果及数据库结果:

139fbd0545c01c5047f2dd29cc9706d8.png    

3f543389be36e237879fb06856a86b5e.png

分析:执行提交后数据就真正写入数据库了,另外通过id是6可以看出,刚才没有提交的事务虽然没有写入数据库,但是却消耗了一个自增的id。

6.测试mysqli::rollback()

将上面的commit()换成rollback()

69c5a8ac3fa60e0848d784a6dd461da6.png

if (mysqli_connect_errno()) {printf("Connect failed: %s\n", mysqli_connect_error());exit();

}/*set charset*/

$sql_set_charset = "set names utf8";$query = $mysqli->query($sql_set_charset);if($query===false) {echo 'set charset failed
';exit(0);

}/*关闭自动提交,开始事务*/

$mysqli->autocommit(false);/*insert*/

$sql_1 = "insert into transaction_test(`content`) values('沈阳')";$query1 = $mysqli->query($sql_1);if($query1===false) {echo 'query1 failed
';

}else{printf("insert_id one: %d
", $mysqli->insert_id);

}/*事务回滚*/

$mysqli->rollback();$mysqli->close();?>

69c5a8ac3fa60e0848d784a6dd461da6.png

运行效果及数据库结果:

cfb8994f4ce82c673454c260edf4ad41.png  

2eaaff92e3fa7b84ec8c291754eb76f4.png

分析:同样是返回的id是7,但数据库没有插入这条记录。那这跟上面的不写rollback()的结果不是一样吗?肯定不一样,继续测试。

7.继续测试rollback()

把上面代码的rollback()去掉,在上面的insert语句的query之后,修改autocommit为true,因为一个事务完成之后还要执行其他的sql语句,要把自动提交恢复到默认状态,然后再执行一次insert语句。

69c5a8ac3fa60e0848d784a6dd461da6.png

if (mysqli_connect_errno()) {printf("Connect failed: %s\n", mysqli_connect_error());exit();

}/*set charset*/

$sql_set_charset = "set names utf8";$query = $mysqli->query($sql_set_charset);if($query===false) {echo 'set charset failed
';exit(0);

}/*关闭自动提交,开始事务*/

$mysqli->autocommit(false);/*insert*/

$sql_1 = "insert into transaction_test(`content`) values('沈阳')";$query1 = $mysqli->query($sql_1);if($query1===false) {echo 'query1 failed
';

}else{printf("insert_id one: %d
", $mysqli->insert_id);

}/*事务回滚

$mysqli->rollback();*/

/*恢复自动提交*/

$mysqli->autocommit(true);/*insert*/

$sql_2 = "insert into transaction_test(`content`) values('长春')";$query2 = $mysqli->query($sql_2);if($query2===false) {echo 'query2 failed
';

}else{printf("insert_id two: %d
", $mysqli->insert_id);

}$mysqli->close();?>

69c5a8ac3fa60e0848d784a6dd461da6.png

运行效果及数据库结果:

2f4733e43ec40270423aef78b07e9515.png  

850520b48b86fcfa68f099dd16a64c1e.png

分析:虽然前面开启了事务,但是自动提交恢复默认之后,第一条insert语句同样写进了数据库,所以不写rollback()并没有回滚。

8 继续测试rollback()

将上面代码中的rollback()的注释去掉

69c5a8ac3fa60e0848d784a6dd461da6.png

if (mysqli_connect_errno()) {printf("Connect failed: %s\n", mysqli_connect_error());exit();

}/*set charset*/

$sql_set_charset = "set names utf8";$query = $mysqli->query($sql_set_charset);if($query===false) {echo 'set charset failed
';exit(0);

}/*关闭自动提交,开始事务*/

$mysqli->autocommit(false);/*insert*/

$sql_1 = "insert into transaction_test(`content`) values('沈阳')";$query1 = $mysqli->query($sql_1);if($query1===false) {echo 'query1 failed
';

}else{printf("insert_id one: %d
", $mysqli->insert_id);

}/*事务回滚*/

$mysqli->rollback();/*恢复自动提交*/

$mysqli->autocommit(true);/*insert*/

$sql_2 = "insert into transaction_test(`content`) values('长春')";$query2 = $mysqli->query($sql_2);if($query2===false) {echo 'query2 failed
';

}else{printf("insert_id two: %d
", $mysqli->insert_id);

}$mysqli->close();?>

69c5a8ac3fa60e0848d784a6dd461da6.png

运行效果及数据库结果:

b4d0e7c510ec86cd9d43fe0e5fe64f81.png  

2c436044a80a41d8fea6584136017a3f.png

分析:id为10的记录没有插入到数据库,这次执行回滚了。

--------------------------------------------------------------------------------------------------------------

9 基于以上的测试,应该对autocommit(),commit(),rollback()有一个比较深的认识了,最后贴一段代码模拟一下真实环境

69c5a8ac3fa60e0848d784a6dd461da6.png

1 <?php2 $mysqli = new mysqli("localhost", "root", "", "test");3

4 /*check connection*/

5 if (mysqli_connect_errno()) {6 printf("Connect failed: %s\n", mysqli_connect_error());7 exit();8 }9

10 /*set charset*/

11 $sql_set_charset = "set names utf8";12 $query = $mysqli->query($sql_set_charset);13 if($query===false) {14 echo 'set charset failed
';15 exit(0);16 }17

18 /*关闭自动提交,开始事务*/

19 $mysqli->autocommit(false);20

21 /*insert*/

22 $commit = true;23 $sql_array = array("insert into transaction_test(`content`) values('石家庄')","insert into transaction_test(`content2`) values('郑州')");24 foreach($sql_array as $key=>$item) {25 $query = $mysqli->query($item);26 if($query===false) {27 /*事务回滚*/

28 printf("query failed : %d
", $key);29 $mysqli->rollback();30 $commit = false;31 break;32 } else{33 printf("insert_id $key: %d
", $mysqli->insert_id);34 }35 }36

37 /*提交事务*/

38 if($commit) {39 $mysqli->commit();40 }41

42 /*恢复自动提交*/

43 $mysqli->autocommit(true);44

45 /*insert*/

46 $sql_2 = "insert into transaction_test(`content`) values('最后插入')";47 $query2 = $mysqli->query($sql_2);48 if($query2===false) {49 echo 'query2 failed
';50 } else{51 printf("insert_id two: %d
", $mysqli->insert_id);52 }53

54 $mysqli->close();55 ?>

69c5a8ac3fa60e0848d784a6dd461da6.png

分析:上面的代码中23行的两条sql语句都是正确的,测试的时候可以这样测:两条都正确,1正确2不正确,1不正确2正确,1和2都不正确。

结果:(只有两条都正确的时候才会真正写入数据库,其他3种情况都回滚了)

分享到:

18e900b8666ce6f233d25ec02f95ee59.png

72dd548719f0ace4d5f9bca64e1d7715.png

2013-04-28 16:58

浏览 218

评论

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值