MySQL数据库中的事务

案例场景思考

乔峰着急用钱,欲将游戏装备中的“汗血宝马”以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);
  1. 判断张无忌是否有180元

    select money from user where username = '张无忌';
  2. 从张无忌的账户中转出180元

    update user set money=money-180 where username = '张无忌';
  3. 向乔峰的账户中转入同样的数额

    update user set money=money+180 where username = '乔峰';
  4. 把“汗血宝马”的拥有者变成张无忌
    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);
}