PHP实现mysql事务处理

12 篇文章 0 订阅

想要实现事务管理,操作的表引擎类型必须是 InnoDB 类型,在生成表的时候就要声明,因为 mysql 默认引擎是 MYISAM ;当然,你也可以在生成表之后修改表的引擎:

ALTER TABLE orders ENGINE=INNODB;

更多详细可以参照我的另一篇博客:《关于mysql管理事务处理》,这里用到的表都是那篇博客中创建的表。

下面先写一个小栗子(往orders表和orderdetail表存数据):

<?php
//数据库连接
$link = mysql_connect("localhost",'root','root') or die("数据库链接失败!");
//选择数据库
// $db = mysql_select_db("test_mysql",$link);
$db = mysql_query("USE test");
if(!$db){
    echo "数据库连接失败!";
}
mysql_query("SET NAMES UTF8");

//开启事务
$sql1 = "START TRANSACTION";
mysql_query($sql1);

$ins_sql1 = "INSERT INTO orders(user_id,order_no) VALUES(10,'LSGO123')";
$err1 = mysql_query($ins_sql1);

$ins_sql2 = "INSERT INTO orderdetail(order_no,detail) VALUES('LSGO123','LSGO实验室')";
$err2 = mysql_query($ins_sql2);

if(!$err1 || !$err2){
    echo "存表出错了";
    mysql_query("ROLLBACK");
}else{
    echo "存表正确";
    mysql_query("COMMIT");
}

mysql_close();
?>

结果输出“存表正确。”,检查数据库:

mysql> SELECT * FROM orders;
+----+---------+----------+
| id | user_id | order_no |
+----+---------+----------+
| 30 |      10 | LSGO123  |
+----+---------+----------+
1 row in set

mysql> SELECT * FROM orderdetail;
+----+----------+----------+
| id | order_no |  detail  |
+----+----------+----------+
| 12 | LSGO123  | LSGO实验室|
+----+----------+----------+
1 row in set

这证明我们存表确实成功。

现在我们卡一下,使其中的一个表存失败:

$ins_sql1 = "INSERT INTO orders(user_id,order_no) VALUES(10,'LSGO123')";
$err1 = mysql_query($ins_sql1);

$ins_sql2 = "INSERT INTO orderdetail(order_no,detail) VALUES('LSGO123',LSGO实验室)";//这里我故意使出错。
$err2 = mysql_query($ins_sql2);

if(!$err1 || !$err2){
    echo "存表出错了";
    mysql_query("ROLLBACK");
}else{
    echo "存表正确";
    mysql_query("COMMIT");
}

结果返回“存表失败了”,检查两张表,发现都没存进去,证明事务起作用了。
通过以上的例子,我们可以看到,事务处理可以用来维护数据库的完整性,它保证成批的MySQL操作要么完全执行,要么完全不执行,也就是说当要求某几个表同时存或同时不存的时候,就该用事务了。

现在该说一下事务里面的保留点

引用前面说的那篇博客里面一个例子:
现在假想这么一个问题,当一个新用户购买我的东西的时候,我要分别存customer表、orders表、orderdetail表,假如某个故障阻止了这个存储过程,那么数据库会发生什么?
1、customer表存失败了,那么我们就不能让它继续往orders和orderdetail表存。
2、customer成功了,但orders表失败了,那么customer是可以允许成功的,毕竟某个用户没有订单是完全合法的,但是orders失败了,orderdetail就不能往下存了,因为orders和orderdetail是同步的。

怎么实现?这里用保留点实现部分回退事务。

//开启事务
$sql1 = "START TRANSACTION";
mysql_query($sql1);

$ins_sql3 = "INSERT INTO customer(name,age) VALUES('奔跑吧LSGO',20)";
$err3 = mysql_query($ins_sql3);

//设置保留点
mysql_query("SAVEPOINT ins_1_2");

$ins_sql1 = "INSERT INTO orders(user_id,order_no) VALUES(10,'LSGO123')";
$err1 = mysql_query($ins_sql1);

$ins_sql2 = "INSERT INTO orderdetail(order_no,detail) VALUES('LSGO123','LSGO实验室')";
$err2 = mysql_query($ins_sql2);

if(!$err1 || !$err2){
    //回滚至保留点处,即不存orders表和orderdetail表
    echo "orders和orderdetail存失败了!";
    mysql_query("ROLLBACK TO SAVEPOINT ins_1_2");
}
if($err3){
    echo "存表成功!";
    mysql_query("COMMIT");
}else{
    echo "customer存失败了!";
    mysql_query("ROLLBACK");
}

结果返回“存表成功”,就是整个事务都成功,三个表自然也存了;

再来?

//开启事务
$sql1 = "START TRANSACTION";
mysql_query($sql1);

$ins_sql3 = "INSERT INTO customer(name,age) VALUES(奔跑吧LSGO,20)";//注意,这里我故意让他出错
$err3 = mysql_query($ins_sql3);

//设置保留点
mysql_query("SAVEPOINT ins_1_2");

$ins_sql1 = "INSERT INTO orders(user_id,order_no) VALUES(10,'LSGO123')";
$err1 = mysql_query($ins_sql1);

$ins_sql2 = "INSERT INTO orderdetail(order_no,detail) VALUES('LSGO123','LSGO实验室')";
$err2 = mysql_query($ins_sql2);

if(!$err1 || !$err2){
    //回滚至保留点处,即不存orders表和orderdetail表
    echo "orders或orderdetail存失败了!";
    mysql_query("ROLLBACK TO SAVEPOINT ins_1_2");
}
if($err3){
    echo "存表成功!";
    mysql_query("COMMIT");
}else{
    echo "customer存失败了!";
    mysql_query("ROLLBACK");
}

结果返回“customer存失败了!”,按照问题的要求,customer表失败,其它两个表也失败了,事实上也是这样的,orders表和orderdetail表没有存。

当我使保留点后的代码出错,结果返回“orders或orderdetail存失败了!”,然后看数据库,发现customer表存成功了,其它两表存失败了。这也满足了问题的要求。

在网上看到一篇博客说在表引擎不是INNODB的情况下,我们也可以实现简单的事务处理,这里就叫它 “仿事务”吧,原理就是把mysql自动提交更改关掉,手动提交代码,就类似于手动COMMIT。
直接上代码:

mysql_query("SET AUTOCOMMIT=0"); //设置mysql不自动提交,需自行用commit语句提交
$sql1 = "INSERT INTO customer(name,age) VALUES('LSGO实验室',20)";
$sql2 = "INSERT INTO orders(user_id,order_no) VALUES(12,'LSGO123')";
$res1 = mysql_query($sql1);
$res2 = mysql_query($sql2); 
if($res1 && $res2){
    mysql_query("COMMIT");
    echo '提交成功。';
}else{
    mysql_query("ROLLBACK");
    echo '数据回滚。';
}
mysql_query("SET AUTOCOMMIT=1"); 
//事务处理完时别忘记mysql_query("SET AUTOCOMMIT=1");恢复自动提交,不然会影响到后面的操作

这个方法固然是走得通的,但是没法实现部分回退的功能,因此还是推荐用前面介绍的方法。

事务处理在thinkphp 中相当简单,毕竟thinkphp中已经封装好相关方法,你只需要调用即可。

//实例化的数据库对象
$model = new Model();
//开启事务
$model->startTrans();
//这里你也可以用具体的一张表的实例即可,如
//$orders = M('Orders');
//$orders->startTrans();

//数据操作
$orders = M('Orders');
$customer = M('Customer');
$res1 = $orders->where("user_id = 10")->delete();
$res2 = $customer->where("age = 20")->delete();

if($res1 && $res2){
    echo "成功啦!";
    $model->commit();
}else{
    echo "滚~~~";
    $model->rollback();
}

至此,我掌握的事务处理已经讲完了。

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值