倒着思考。杜绝纯粹的知识填鸭教育
少废话,是上代码:
update table1 set money-100 where id=1; //A账户减少100元
update table2 set money+100 where id=2; //B 账户增加100元
问题:这是一个简单的银行转账案例sql,由于服务器等未知原因,可能出现两条sql一个执行成功一个执行失败的情况下,一个账户没有成功增加100元,另一个账户缺减少了100元。要实现这两条sql语句必须都要成功或者都要失败。请问让你设计一种方案,怎么去着手?
初步思考方案一:每条sql语句都加判断,是否成功,失败就不再往下走
if(!mysql_query(update table1 set money-100 where id=1)){
//失败就停止退出
}
if(!mysql_query(update table1 set money-100 where id=1)){
//失败就停止退出
}
总结:仔细想,如果第一条语句执行成功了,而第二条语句执行失败了呢?
还不严谨。由此进一步考量,应该是无论哪条语句执行失败,都要能撤销已执行全部的操作。
设想:假如有这么一条命令叫做rollback,可以撤销已执行的全部操作。
那么修改后的方案二:
if(!mysql_query(update table1 set money-100 where id=1)){
//撤销
rollback
exit;
}
if(!mysql_query(update table1 set money-100 where id=1)){
//撤销
rollback
exit;
}
总结:貌似应该没问题了。再揣摩发现,我们撤销操作,应该是撤销到哪才算呢?不能把更早之前的所有执行的sql都撤销掉吧,起码有个位置。怎么办?在这两条语句前,加一个开始命令,只撤销到开始位置。
设想:有一个begin的开始命令。
那么修改后的方案三:
mysql_query(begin)
if(!mysql_query(update table1 set money-100 where id=1)){
//撤销
rollback
exit;
}
if(!mysql_query(update table1 set money-100 where id=1)){
//撤销
rollback
exit;
}
总结:这下貌似是真的可以了,再仔细揣摩发现,还有点问题,假如第一条语句执行成功了,突然服务器宕机了,命令没有再往下走,仍然是不行的。怎么办?在末尾加一个收尾的命令,如果mysql能执行到这条命令,那么才算真正完成数据更新了,不然以前的操作还都不算。
设想:有一个叫commit的收尾的命令
那么修改后的方案四:
mysql_query(begin)
if(!mysql_query(update table1 set money-100 where id=1)){
//撤销
rollback
exit;
}
if(!mysql_query(update table1 set money-100 where id=1)){
//撤销
rollback
exit;
}
mysql_query(commit)
-------------------------------------------------------------------------------------------------------------------------------
正着学习。弥补严谨自己的思维逻辑
学习下mysql中给我的解决方案,它把上述我们解决的问题叫做事务处理。
同样mysql为了解决上述的问题,也有三个命令,分别是begin、rollback、commit
一样的:
begin; //开启事务
update table1 set money-100 where id=1; //A账户减少100元
update table2 set money+100 where id=2; //B 账户增加100元
commit; //提交事务
准确的说:凡是事务内的语句,只要能被mysql接收到,都能保证全部执行,但是但是并不能保证都执行成功。失败时,需要自己主动去判断主动去回滚。(极其错误的认知:认为只要把事务写出来,最后用commit提交一下,数据库会自动判断这些语句是否全执行成功,如果成功则把所有的数据插入到数据库,如果有一条失败就自动回滚至原始状态!)
严格的事务使用流程案例演示
If(!mysql_query(begin)){
//如果事务没开启成功,那么后面的语句真的就是真实执行了,需要 主动判断一下
//退出
exit;
}
If(!mysql_query(update table1 set money-100 where id=1)){
//回滚
rollback
// 退出
}
If(!mysql_query(update table2 set money+100 where id=2)){
//回滚
rollback
//退出
}
If(!mysql_query(commit)){
//回滚
rollback //如果客户端把commit已经发送到了mysql执行,失败了,最好
也要判断主动立即去回滚,虽然数据库最终会慢慢自动回滚。因为事
务一直未提交,上面执行的写操作语句会给当前操作数据锁住,其
他用户不能操作这条数据,直到等待事务结束才能。(提交或回滚)。
}
有时候,根据业务需要,我们对操作的数据需要保持一个较高的一致性,可以考虑使用事务。
付费小密圈
1、解答大家php学习开发过程的问题
2、 分享不同php项目实战经验
3、定期邀请大牛进圈做知识分享
4、持续分享优质php知识教程