案例场景思考
乔峰着急用钱,欲将游戏装备中的“汗血宝马”以100Q币的价格转让与张无忌。
# 表设计
CREATE TABLE goods(
id TINYINT PRIMARY KEY AUTO_INCREMENT,
goods_name VARCHAR(50),
price DECIMAL(7,2),
`owner` TINYINT
)ENGINE=INNODB;
CREATE TABLE `user`(
id TINYINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50),
money DECIMAL(7,2)
)ENGINE=INNODB;
INSERT INTO user(username,money) VALUES('乔峰',5);
INSERT INTO user(username,money) VALUES('张无忌',300);
INSERT INTO goods(goods_name,price,OWNER) VALUES('汗血宝马',180,1);
-
判断张无忌是否有180元
select money from user where username = '张无忌';
-
从张无忌的账户中转出180元
update user set money=money-180 where username = '张无忌';
-
向乔峰的账户中转入同样的数额
update user set money=money+180 where username = '乔峰';
- 把“汗血宝马”的拥有者变成张无忌
update goods set owner=2 where goods_name = '汗血宝马' and owner = 1;
思考问题: 假如:2/3/4中有一条SQL执行其他SQL执行成功 会出现什么效果
解决方案
use jkfw;
START TRANSACTION; /*也可 begin*/
UPDATE USER SET money=money-180 WHERE username = '张无忌';
UPDATE USER SET money=money+180 WHERE username = '乔峰';
UPDATE goods SET OWNER=2 WHERE goods_name = '汗血宝马' AND OWNER = 1;
ROLLBACK;
select * from user;
select * from goods;
UPDATE USER SET money=money-180 WHERE username = '张无忌';
UPDATE USER SET money=money+180 WHERE username = '乔峰';
UPDATE goods SET OWNER=2 WHERE goods_name = '汗血宝马' AND OWNER = 1;
commit; /*提交*/
select * from user;
select * from goods;
一、什么是事务
事务是由一个或多个SQL语句组成的集合里,每个SQL语句相互依赖,如何某条SQL语句一旦执行失败或产生错误,这个集合将会回滚。所有受影响的数据将返回事务开始以前的状态。如果集合中的所有SQL都执行成功,则事务被顺利执行
# MYSQL中只有INNODB和BDB类型的数据表才能支持事务处理!其他的类型是不支持的!
SHOW ENGINES;
二、事务的四个属性
-
原子性: 事务是由一个或一组SQL相关关联组成。这些集合被认为是一个不可分割的单元
-
一致性: 事务的操作应该使数据库从一个状态转变到另一个的状态。例如:网购,即让商品出库,又让商品进入顾客的购物车才算是事务
-
隔离性: 每个事务都有自己的空间,和其他发生在系统中的事务隔离开来。一个事务处理后的结果,影响了其他事务,那么其他事务会撤回。
- 持久性: 事务提交之后对数据的操作是永久的。在MySQL中如果系统崩溃或者数据存储介质破坏,通过日志,系统能够恢复在重启前进行的最后一次成功更新,可以反应系统崩溃时处于执行过程的事务的变化
三、PHP中使用事务
# 开启事务
mysqli_query($link,'START TRANSACTION');
$haveError = false;
# 主表新增
$sql = "INSERT INTO member(account,password) VALUES ('{$username}','{$password}')";
$result = mysqli_query($link,$sql);
if(!$result){
$haveError = true;
}
# 副表添加
$member_id = mysqli_insert_id($link);
$sql = "INSERT INTO member_f(id22,phone) VALUES ($member_id,'{$password}')";
$result2 = mysqli_query($link,$sql);
if( !$result2 ){
$haveError = true;
logs(mysqli_error($link));
}
if($haveError){
mysqli_query($link,'ROLLBACK');
# 写入日志 发邮件、发微信消息给程序员
exit('注册失败');
}else{
mysqli_query($link,'commit');
exit('注册成功');
}
###################
if( $haveError ){
mysqli_rollback($link);
}else{
mysqli_commit($link);
}