Skip to content

[后端开发]数据库事务处理 #40

@matafela

Description

@matafela

1. 简单的介绍

举个例子吧,我去世博天津包子那里买早餐,柜台里一个有着娃娃脸的小哥在刷卡机上打了3.5元,在我把卡放上刷卡机的一瞬间,机子完成了:

a. (stepA)从我的卡扣除了3.5元

b. (stepB)向世博的账户添加了3.5元(姑且当作是这样吧po)

共计两个操作。如果我的卡余额被扣世博的账户却没有钱进账,或者世博的账户余额增加了但是我的卡却没有被扣钱,都是一件很尴尬的事。
不过数据库事务这种东西的诞生就是为了不让这样的尴尬事出现。
拿Mysql来举例的话,stepA和stepB可以分别对应一条SQL语句,现在启动一个事务,然后分别加载stepA和stepB两条SQL语句。提交事务后,如果有其中任何一条不成功,整个事务就会回滚,就是说我的学生卡的余额和世博账户的余额都会恢复到我刷卡之前的样子。
然后给出事务处理的定义:(虽然并不知道例子有没有用,但是我还是举了。只是单纯的想举一下而已)

数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。事务是数据库运行中的一个逻辑工作单位,由DBMS中的事务管理子系统负责事务的处理。(百度百科上找的* ^ *)

2. PHP&Mysql中的数据库事务处理的使用

以下使用PDO来处理(Mysqli我自己用起来自己也不习惯_^_),虽然代码是抄的,不过自己打了一遍貌似有用。
代码来源http://www.oschina.net/code/snippet_561584_12903
还有数据库的存储引擎(Storage Engine)记得设置为InnoDB,貌似MyISAM不支持哎,然而它居然是MySql默认的引擎(╯-_-)╯╧╧

<?php

    //pdo 实现mysql 事务处理 简单示例
    /*
        实现向数据库中写入多条数据的事务
        insert into test values ('test123', 'test123')
    */

    $type     = 'mysql';        //要连接的数据库类型
    $host     = 'localhost';    //数据库主机
    $dbname   = 'test';         //要选择的数据库名称
    $password = '';
    $username = 'root';

    $dsn = "{$type}:dbname={$dbname};host={$host}";

try{

    //连接数据库
    $pdo = new PDO($dsn, $username, $password);

    //编码
    $pdo->exec("set names utf8");

    //设置错误提示方式
    $pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);

    //开启标准事务
    $pdo->beginTransaction();

    //构造sql语句
    //$sql = "insert into test values (?,?)";
    $sql = "insert into test values (:user, :password)";    
    //或者使用此sql语句 :user :password 与问号功能相似 绑定参数

    $stmt = $pdo->prepare($sql);

    //为sql语句中的变量绑定变量
    $stmt->bindParam(':user', $username);
    $stmt->bindParam(':password', $password);

    //为sql语句中的变量 赋值
    $username = 'test123';
    $password = '123456';

    $stmt->execute();

    $rows = $stmt->rowCount();

    if($rows<1){
        //如果失败则抛出异常
        throw new PDOexception('第一句sql语句执行失败!', '01');

    }


    $username = 'hello123';
    $password = '123456';

    $stmt->execute();

    $rows = $stmt->rowCount();

    if($rows<1){
        //如果失败则抛出异常
        throw new PDOexception('第二句sql语句执行失败!', '02');

    }


    $username = 'world123';
    $password = '123456';

    $stmt->execute();

    $rows = $stmt->rowCount();

    if($rows<1){
        //如果失败则抛出异常
        throw new PDOexception('第三句sql语句执行失败!', '02');

    }

    //如果没有异常被抛出则 sql语句全部执行成功 提交事务
    $pdo->commit();


}catch(PDOexception $e){

    //如果有异常被抛出 则事务失败 执行事务回滚
    $pdo->rollback();

    //输出异常信息
    echo $e->getCode().'-----'.$e->getMessage();

    $pdo = null;

}
  ?>

3. ThinkPHP中的事务处理

在官方文档(ThinkPHP5.0)里面看到了,顺便贴上来。
官方文档http://www.kancloud.cn/manual/thinkphp5/139063

自动控制事务处理

Db::transaction(function(){
    Db::table('think_user')->find(1);
    Db::table('think_user')->delete(1);
});

也可以手动控制事务,例如:

// 启动事务
Db::startTrans();
try{
    Db::table('think_user')->find(1);
    Db::table('think_user')->delete(1);
    // 提交事务
    Db::commit();    
catch (\PDOException $e) {
    // 回滚事务
    Db::rollback();
}

如果你使用了多个事务的嵌套,注意在开启事务的时候添加事务标识,避免在内部被提前提交,例如:

// 启动事务
Db::startTrans('UserTrans');
try{
    Db::table('think_user')->find(1);
    Db::table('think_user')->delete(1);
    // 提交事务
    Db::commit('UserTrans');    
catch (\PDOException $e) {
    // 回滚事务
    Db::rollback();
}

就酱把。
因为学的少,接触的数据库和语言也不多,所以只好放上这些了。

这篇文章有点复杂,但是看上去有点意思http://blog.csdn.net/zdwzzu2006/article/details/5947062

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions