PHP MySQL事务

时间:2019-11-20 08:52:38  来源:igfitidea点击:

简介:在本教程中,您将学习如何在PHP中处理MySQL事务以确保数据库的数据完整性。

事务是一组相互依赖的SQL语句,需要以全有或全无模式执行。
如果所有SQL语句成功执行,则事务成功。
任何语句失败都会触发系统回滚到原始状态,以避免数据不一致。

交易的经典示例是从一个银行帐户到另一个银行帐户的汇款交易。
它需要三个步骤:

  • 检查已转帐帐户的余额,以查看该金额是否足以进行转帐。

  • 如果金额足够,请从转帐的余额中扣除该金额。

  • 将转帐金额添加到收款帐户的余额中。

如果第二步出错,则第三步不应继续。
另外,如果在第三步中发生错误,则第二步必须逆转。
如果发生故障,两个银行帐户的金额均保持不变,或者如果交易成功完成,则可以正确调整。

PHP中的MySQL事务

当您使用PDO创建与支持事务的数据库的连接时,将设置自动提交模式。
这意味着您发出的每个查询都包装在一个隐式事务中。

请注意,并非MySQL中的所有存储引擎都支持事务,例如MyISAM不支持事务,但是InnoDB支持。

要在PHP中处理MySQL事务,请使用以下步骤:

  • 通过调用PDO对象的beginTransaction()方法来启动事务。

  • 将SQL语句和commit()方法调用放在try块中。

  • 通过调用PDO对象的rollBack()方法在catch块中回滚事务。

PHP MySQL交易示例

我们将创建一个名为accounts的表,以演示两个银行帐户之间的资金转移。

首先,执行以下语句创建accounts表:

CREATE TABLE accounts (
    id     INT AUTO_INCREMENT PRIMARY KEY,
    name   VARCHAR (50)    NOT NULL,
    amount DECIMAL (19, 4) NOT NULL
);

第二,在accounts表中插入两行:

INSERT INTO accounts(name,amount)
VALUES('John',25000),
      ('Mary',95000);

三,查询账户表:

SELECT *
  FROM accounts;

让我们看一下下面的TransactionDemo类:

<?php

/**
 * PHP MySQL Transaction Demo
 */
class TransactionDemo {

    const DB_HOST = 'localhost';
    const DB_NAME = 'classicmodels';
    const DB_USER = 'root';
    const DB_PASSWORD = '';

    /**
     * Open the database connection
     */
    public function __construct() {
        // open database connection
        $conStr = sprintf("mysql:host=%s;dbname=%s", self::DB_HOST, self::DB_NAME);
        try {
            $this->pdo = new PDO($conStr, self::DB_USER, self::DB_PASSWORD);
        } catch (PDOException $e) {
            die($e->getMessage());
        }
    }

    /**
     * PDO instance
     * @var PDO 
     */
    private $pdo = null;

    /**
     * Transfer money between two accounts
     * @param int $from
     * @param int $to
     * @param float $amount
     * @return true on success or false on failure.
     */
    public function transfer($from, $to, $amount) {

        try {
            $this->pdo->beginTransaction();

            // get available amount of the transferer account
            $sql = 'SELECT amount FROM accounts WHERE id=:from';
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute(array(":from" => $from));
            $availableAmount = (int) $stmt->fetchColumn();
            $stmt->closeCursor();

            if ($availableAmount < $amount) {
                echo 'Insufficient amount to transfer';
                return false;
            }
            // deduct from the transferred account
            $sql_update_from = 'UPDATE accounts
				SET amount = amount - :amount
				WHERE id = :from';
            $stmt = $this->pdo->prepare($sql_update_from);
            $stmt->execute(array(":from" => $from, ":amount" => $amount));
            $stmt->closeCursor();

            // add to the receiving account
            $sql_update_to = 'UPDATE accounts
                                SET amount = amount + :amount
                                WHERE id = :to';
            $stmt = $this->pdo->prepare($sql_update_to);
            $stmt->execute(array(":to" => $to, ":amount" => $amount));

            // commit the transaction
            $this->pdo->commit();

            echo 'The amount has been transferred successfully';

            return true;
        } catch (PDOException $e) {
            $this->pdo->rollBack();
            die($e->getMessage());
        }
    }

    /**
     * close the database connection
     */
    public function __destruct() {
        // close the database connection
        $this->pdo = null;
    }

}

// test the transfer method
$obj = new TransactionDemo();

// transfer 30K from from account 1 to 2
$obj->transfer(1, 2, 30000);

// transfer 5K from from account 1 to 2
$obj->transfer(1, 2, 5000);

我们使用__construct()方法打开数据库连接,并使用__destruct()方法关闭数据库连接。
在transfer()方法中:

  • 首先,我们查询转帐帐户的金额并将其与转帐金额进行比较,以检查转帐帐户的余额是否足够。

  • 其次,在金额足够的情况下,我们从已转帐帐户中扣除转帐金额,并将其添加到接收帐户中。

  • 第三,我们通过调用commit()方法来提交事务。
    如果发生任何错误,我们在catch块中调用rollBack()方法以回滚事务。

让我们测试transfer()方法。

// transfer 30K from from account 1 to 2
$obj->transfer(1, 2, 30000);

我们从John的帐户中将3万转移到了Mary的帐户中。
我们收到以下消息:

Insufficient amount to transfer

再进行一次转移:

// transfer 5K from from account 1 to 2
$obj->transfer(1, 2, 5000);

该脚本返回以下消息:

The amount has been transferred successfully.

我们已成功在两个银行帐户之间转帐。

您可以通过以下链接下载源代码:

下载PHP MySQL事务源代码

在本教程中,我们逐步向您展示了如何在PHP中处理MySQL事务以确保数据完整性。