PDOPHP拡張機能を使用してUbuntu18.04のPHPでMySQLトランザクションを実行する方法
序章
MySQL トランザクションは、データベース内で単一のユニットとして実行される、論理的に関連するSQLコマンドのグループです。 トランザクションは、アプリケーションで ACID(原子性、一貫性、分離、および耐久性)コンプライアンスを実施するために使用されます。 これは、データベースでの処理操作の信頼性を管理する一連の標準です。
Atomicityは、関連するトランザクションの成功、またはエラーが発生した場合の完全な失敗を保証します。 一貫性は、定義されたビジネスロジックに従ってデータベースに送信されたデータの有効性を保証します。 分離とは、データベースに接続しているさまざまなクライアントの影響が相互に影響しないようにする同時トランザクションの正しい実行です。 耐久性により、論理的に関連するトランザクションがデータベースに永続的に残ります。
トランザクションを介して発行されたSQLステートメントは、成功するか、完全に失敗する必要があります。 クエリのいずれかが失敗した場合、MySQLは変更をロールバックし、データベースにコミットされることはありません。
MySQLトランザクションがどのように機能するかを理解するための良い例は、eコマースWebサイトです。 顧客が注文すると、アプリケーションは次のようないくつかのテーブルにレコードを挿入します。 orders
と orders_products
、ビジネスロジックによって異なります。 単一の注文に関連するマルチテーブルレコードは、単一の論理ユニットとしてデータベースにアトミックに送信する必要があります。
もう1つのユースケースは、銀行のアプリケーションです。 クライアントが送金しているとき、いくつかのトランザクションがデータベースに送信されます。 送信者のアカウントから借方に記入され、受信者のパーティアカウントに貸方記入されます。 2つのトランザクションは同時にコミットする必要があります。 それらの1つに障害が発生した場合、データベースは元の状態に戻り、変更をディスクに保存する必要はありません。
このチュートリアルでは、 PDO PHP拡張機能を使用します。これは、PHPでデータベースを操作するためのインターフェイスを提供し、Ubuntu18.04サーバーでMySQLトランザクションを実行します。
前提条件
始める前に、次のものが必要になります。
- Ubuntu 18.04を使用した初期サーバーセットアップに従ってセットアップされた1つのUbuntu18.04サーバー(sudo非rootユーザーを含む)。
- システムにインストールされているApache、MySQL、およびPHP。 Linux、Apache、MySQL、PHP(LAMP)スタックをUbuntu18.04にインストールする方法に関するガイドに従うことができます。 手順4(仮想ホストの設定)をスキップして、デフォルトのApache設定を直接操作できます。
ステップ1—サンプルデータベースとテーブルの作成
MySQLトランザクションの操作を開始する前に、まずサンプルデータベースを作成し、いくつかのテーブルを追加します。 まず、rootとしてMySQLサーバーにログインします。
- sudo mysql -u root -p
プロンプトが表示されたら、MySQLルートパスワードを入力して、 ENTER
続行します。 次に、データベースを作成します。このチュートリアルでは、データベースを呼び出します。 sample_store
:
- CREATE DATABASE sample_store;
次の出力が表示されます。
OutputQuery OK, 1 row affected (0.00 sec)
と呼ばれるユーザーを作成します sample_user
あなたのデータベースのために。 交換することを忘れないでください PASSWORD
強い価値を持つ:
- CREATE USER 'sample_user'@'localhost' IDENTIFIED BY 'PASSWORD';
ユーザーに完全な権限を発行します sample_store
データベース:
- GRANT ALL PRIVILEGES ON sample_store.* TO 'sample_user'@'localhost';
最後に、MySQL特権をリロードします。
- FLUSH PRIVILEGES;
ユーザーを作成すると、次の出力が表示されます。
OutputQuery OK, 0 rows affected (0.01 sec)
. . .
データベースとユーザーを配置すると、MySQLトランザクションがどのように機能するかを示すためのいくつかのテーブルを作成できるようになります。
MySQLサーバーからログアウトします。
- QUIT;
システムがログアウトすると、次の出力が表示されます。
OutputBye.
次に、の資格情報を使用してログインします sample_user
作成したばかり:
- sudo mysql -u sample_user -p
のパスワードを入力します sample_user
とヒット ENTER
続行します。
に切り替えます sample_store
現在選択されているデータベースにするには:
- USE sample_store;
選択すると、次の出力が表示されます。
OutputDatabase Changed.
次に、 products
テーブル:
- CREATE TABLE products (product_id BIGINT PRIMARY KEY AUTO_INCREMENT, product_name VARCHAR(50), price DOUBLE) ENGINE = InnoDB;
このコマンドは、 products
名前の付いたフィールドを持つテーブル product_id
. あなたは BIGINT
最大2^63-1の大きな値に対応できるデータ型。 これと同じフィールドを使用します PRIMARY KEY
製品を一意に識別するため。 The AUTO_INCREMENT
キーワードは、新製品が挿入されたときに次の数値を生成するようにMySQLに指示します。
The product_name
フィールドはタイプです VARCHAR
それは最大まで保持することができます 50
文字または数字。 製品について price
、使用します DOUBLE
10進数の価格で浮動小数点形式に対応するデータ型。
最後に、InnoDBを ENGINE
のような他のストレージエンジンとは対照的に、MySQLトランザクションを快適にサポートするため MyISAM
.
作成したら products
テーブルでは、次の出力が得られます。
OutputQuery OK, 0 rows affected (0.02 sec)
次に、いくつかのアイテムをに追加します products
次のコマンドを実行してテーブルを作成します。
- INSERT INTO products(product_name, price) VALUES ('WINTER COAT','25.50');
- INSERT INTO products(product_name, price) VALUES ('EMBROIDERED SHIRT','13.90');
- INSERT INTO products(product_name, price) VALUES ('FASHION SHOES','45.30');
- INSERT INTO products(product_name, price) VALUES ('PROXIMA TROUSER','39.95');
それぞれの後に次のような出力が表示されます INSERT
手術:
OutputQuery OK, 1 row affected (0.02 sec)
. . .
次に、データが製品テーブルに追加されたことを確認します。
- SELECT * FROM products;
挿入した4つの製品のリストが表示されます。
Output+------------+-------------------+-------+
| product_id | product_name | price |
+------------+-------------------+-------+
| 1 | WINTER COAT | 25.5 |
| 2 | EMBROIDERED SHIRT | 13.9 |
| 3 | FASHION SHOES | 45.3 |
| 4 | PROXIMA TROUSER | 39.95 |
+------------+-------------------+-------+
4 rows in set (0.01 sec)
次に、を作成します customers
顧客に関する基本情報を保持するためのテーブル:
- CREATE TABLE customers (customer_id BIGINT PRIMARY KEY AUTO_INCREMENT, customer_name VARCHAR(50) ) ENGINE = InnoDB;
のように products
テーブル、あなたは使用します BIGINT
のデータ型 customer_id
これにより、テーブルが2^63-1レコードまでの多くの顧客をサポートできるようになります。 キーワード AUTO_INCREMENT
新しい顧客を挿入すると、列の値が増加します。
以来 customer_name
列は英数字値を受け入れます。VARCHARデータ型を使用します。制限は 50
文字。 繰り返しますが、 InnoDB
保管所 ENGINE
トランザクションをサポートします。
前のコマンドを実行して作成した後 customers
表を見ると、次の出力が表示されます。
OutputQuery OK, 0 rows affected (0.02 sec)
3つのサンプル顧客をテーブルに追加します。 次のコマンドを実行します。
- INSERT INTO customers(customer_name) VALUES ('JOHN DOE');
- INSERT INTO customers(customer_name) VALUES ('ROE MARY');
- INSERT INTO customers(customer_name) VALUES ('DOE JANE');
顧客が追加されると、次のような出力が表示されます。
OutputQuery OK, 1 row affected (0.02 sec)
. . .
次に、のデータを確認します customers
テーブル:
- SELECT * FROM customers;
3人の顧客のリストが表示されます。
Output+-------------+---------------+
| customer_id | customer_name |
+-------------+---------------+
| 1 | JOHN DOE |
| 2 | ROE MARY |
| 3 | DOE JANE |
+-------------+---------------+
3 rows in set (0.00 sec)
次に、を作成します orders
さまざまな顧客からの注文を記録するためのテーブル。 を作成するには orders
テーブルで、次のコマンドを実行します。
- CREATE TABLE orders (order_id BIGINT AUTO_INCREMENT PRIMARY KEY, order_date DATETIME, customer_id BIGINT, order_total DOUBLE) ENGINE = InnoDB;
列を使用します order_id
として PRIMARY KEY
. The BIGINT
データ型を使用すると、最大2 ^ 63-1の注文に対応でき、注文を挿入するたびに自動インクリメントされます。 The order_date
フィールドには、注文が行われた実際の日時が保持されるため、 DATETIME
データ・タイプ。 The customer_id
に関連する customers
以前に作成したテーブル。
次の出力が表示されます。
OutputQuery OK, 0 rows affected (0.02 sec)
1人の顧客の注文に複数のアイテムが含まれている可能性があるため、 orders_products
この情報を保持するテーブル。
を作成するには orders_products
テーブルで、次のコマンドを実行します。
- CREATE TABLE orders_products (ref_id BIGINT PRIMARY KEY AUTO_INCREMENT, order_id BIGINT, product_id BIGINT, price DOUBLE, quantity BIGINT) ENGINE = InnoDB;
あなたは ref_id
として PRIMARY KEY
これにより、レコードが挿入されるたびに自動インクリメントされます。 The order_id
と product_id
に関連する orders
そしてその products
それぞれテーブル。 The price
列はデータ型です DOUBLE
浮動値に対応するため。
ストレージエンジン InnoDB
1人の顧客の注文は、トランザクションを使用する複数のテーブルに同時に影響するため、以前に作成した他のテーブルと一致する必要があります。
出力により、テーブルの作成が確認されます。
OutputQuery OK, 0 rows affected (0.02 sec)
にデータを追加することはありません orders
と orders_products
今のところテーブルですが、後でMySQLトランザクションを実装するPHPスクリプトを使用してこれを行います。
MySQLサーバーからログアウトします。
- QUIT;
これでデータベーススキーマが完成し、いくつかのレコードが入力されました。 次に、データベース接続とMySQLトランザクションを処理するためのPHPクラスを作成します。
ステップ2—MySQLトランザクションを処理するためのPHPクラスの設計
このステップでは、PDO(PHPデータオブジェクト)を使用してMySQLトランザクションを処理するPHPクラスを作成します。 クラスはMySQLデータベースに接続し、データベースにアトミックにデータを挿入します。
クラスファイルをApacheWebサーバーのルートディレクトリに保存します。 これを行うには、を作成します DBTransaction.php
テキストエディタを使用したファイル:
- sudo nano /var/www/html/DBTransaction.php
次に、次のコードをファイルに追加します。 交換 PASSWORD
手順1で作成した値を使用します。
<?php
class DBTransaction
{
protected $pdo;
public $last_insert_id;
public function __construct()
{
define('DB_NAME', 'sample_store');
define('DB_USER', 'sample_user');
define('DB_PASSWORD', 'PASSWORD');
define('DB_HOST', 'localhost');
$this->pdo = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME, DB_USER, DB_PASSWORD);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
}
の始まりに向けて DBTransaction
クラスでは、PDOは定数を使用します(DB_HOST
, DB_NAME
, DB_USER
、 と DB_PASSWORD
)ステップ1で作成したデータベースを初期化して接続します。
注:ここではMySQLトランザクションを小規模に示しているため、データベース変数を DBTransaction
クラス。 大規模な本番プロジェクトでは、通常、別の構成ファイルを作成し、PHPrequire_onceステートメントを使用してそのファイルからデータベース定数をロードします。
次に、PDOクラスに2つの属性を設定します。
ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION
:この属性は、エラーが発生した場合に例外をスローするようにPDOに指示します。 このようなエラーは、デバッグのためにログに記録できます。ATTR_EMULATE_PREPARES, false
:このオプションは、プリペアドステートメントのエミュレーションを無効にし、MySQLデータベースエンジンがプリペアドステートメント自体を準備できるようにします。
次に、次のコードをファイルに追加して、クラスのメソッドを作成します。
. . .
public function startTransaction()
{
$this->pdo->beginTransaction();
}
public function insertTransaction($sql, $data)
{
$stmt = $this->pdo->prepare($sql);
$stmt->execute($data);
$this->last_insert_id = $this->pdo->lastInsertId();
}
public function submitTransaction()
{
try {
$this->pdo->commit();
} catch(PDOException $e) {
$this->pdo->rollBack();
return false;
}
return true;
}
}
を押してファイルを保存して閉じます CTRL
+ X
, Y
、 それから ENTER
.
MySQLトランザクションを操作するには、次の3つの主要なメソッドを作成します。 DBTransaction
クラス; startTransaction
, insertTransaction
、 と submitTransaction
.
-
startTransaction
:このメソッドは、トランザクションを開始するようにPDOに指示し、commitコマンドが発行されるまで自動コミットをオフにします。 -
insertTransaction
:このメソッドは2つの引数を取ります。 The$sql
変数は、実行されるSQLステートメントを保持します。$data
変数は、プリペアドステートメントを使用しているため、SQLステートメントにバインドされるデータの配列です。 データは配列としてinsertTransaction
方法。 -
submitTransaction
:このメソッドは、を発行することにより、データベースへの変更を永続的にコミットします。commit()
指図。 ただし、エラーが発生し、トランザクションに問題がある場合、メソッドはrollBack()
PDO例外が発生した場合に、データベースを元の状態に戻すメソッド。
君の DBTransaction
classはトランザクションを初期化し、実行するさまざまなSQLコマンドを準備し、問題がない場合は最後にデータベースへの変更をアトミックにコミットします。それ以外の場合、トランザクションはロールバックされます。 さらに、このクラスではレコードを取得できます order_id
公共施設にアクセスして作成したばかり last_insert_id
.
The DBTransaction
これで、次に作成するPHPコードでクラスを呼び出して使用する準備が整いました。
ステップ3—DBTransactionクラスを使用するためのPHPスクリプトの作成
を実装するPHPスクリプトを作成します DBTransaction
クラスを作成し、SQLコマンドのグループをMySQLデータベースに送信します。 オンラインショッピングカートでの顧客の注文のワークフローを模倣します。
これらのSQLクエリは orders
そしてその orders_products
テーブル。 君の DBTransaction
クラスは、すべてのクエリがエラーなしで実行された場合にのみ、データベースへの変更を許可する必要があります。 そうしないと、エラーが返され、変更を試みた場合はロールバックされます。
顧客に対して単一の注文を作成しています JOHN DOE
customer_idで識別されます 1
. 顧客の注文には、数量が異なる3つの異なるアイテムがあります。 products
テーブル。 PHPスクリプトは、顧客の注文データを取得して、 DBTransaction
クラス。
を作成します orders.php
ファイル:
- sudo nano /var/www/html/orders.php
次に、次のコードをファイルに追加します。
<?php
require("DBTransaction.php");
$db_host = "database_host";
$db_name = "database_name";
$db_user = "database_user";
$db_password = "PASSWORD";
$customer_id = 2;
$products[] = [
'product_id' => 1,
'price' => 25.50,
'quantity' => 1
];
$products[] = [
'product_id' => 2,
'price' => 13.90,
'quantity' => 3
];
$products[] = [
'product_id' => 3,
'price' => 45.30,
'quantity' => 2
];
$transaction = new DBTransaction($db_host, $db_user, $db_password, $db_name);
インスタンスを初期化するPHPスクリプトを作成しました DBTransaction
手順2で作成したクラス。
このスクリプトには、 DBTransaction.php
ファイルとあなたは初期化します DBTransaction
クラス。 次に、顧客が店舗に注文しているすべての製品の多次元配列を準備します。 また、 startTransaction()
トランザクションを開始するメソッド。
次に、次のコードを追加して、 orders.php
脚本:
. . .
$order_query = "insert into orders (order_id, customer_id, order_date, order_total) values(:order_id, :customer_id, :order_date, :order_total)";
$product_query = "insert into orders_products (order_id, product_id, price, quantity) values(:order_id, :product_id, :price, :quantity)";
$transaction->insertQuery($order_query, [
'customer_id' => $customer_id,
'order_date' => "2020-01-11",
'order_total' => 157.8
]);
$order_id = $transaction->last_insert_id;
foreach ($products as $product) {
$transaction->insertQuery($product_query, [
'order_id' => $order_id,
'product_id' => $product['product_id'],
'price' => $product['price'],
'quantity' => $product['quantity']
]);
}
$result = $transaction->submit();
if ($result) {
echo "Records successfully submitted";
} else {
echo "There was an error.";
}
を押してファイルを保存して閉じます CTRL
+ X
, Y
、 それから ENTER
.
を介して注文テーブルに挿入するコマンドを準備します insertTransaction
方法。 この後、パブリックプロパティの値を取得します last_insert_id
から DBTransaction
クラスとして使用します $order_id
.
あなたが持ったら $order_id
、一意のIDを使用して、顧客の注文アイテムを orders_products
テーブル。
最後に、メソッドを呼び出します submitTransaction
問題がなければ、顧客の注文の詳細全体をデータベースにコミットします。 それ以外の場合、メソッド submitTransaction
試行された変更をロールバックします。
今、あなたは実行します orders.php
ブラウザのスクリプト。 以下を実行して置き換えます your-server-IP
サーバーのパブリックIPアドレスを使用します。
http://your-server-IP/orders.php
レコードが正常に送信されたことの確認が表示されます。
PHPスクリプトは期待どおりに機能しており、注文は関連する注文商品とともにデータベースにアトミックに送信されました。
あなたは実行しました orders.php
ブラウザウィンドウ上のファイル。 スクリプトは DBTransaction
順番に提出したクラス orders
データベースへの詳細。 次のステップでは、レコードが関連するデータベーステーブルに保存されているかどうかを確認します。
ステップ4—データベースのエントリを確認する
このステップでは、顧客の注文に対してブラウザウィンドウから開始されたトランザクションが、期待どおりにデータベーステーブルに転記されたかどうかを確認します。
これを行うには、MySQLデータベースに再度ログインします。
- sudo mysql -u sample_user -p
のパスワードを入力します sample_user
とヒット ENTER
続ける。
に切り替えます sample_store
データベース:
- USE sample_store;
次の出力を確認して、続行する前にデータベースが変更されていることを確認してください。
OutputDatabase Changed.
次に、次のコマンドを発行して、からレコードを取得します。 orders
テーブル:
- SELECT * FROM orders;
これにより、顧客の注文の詳細を示す次の出力が表示されます。
Output+----------+---------------------+-------------+-------------+
| order_id | order_date | customer_id | order_total |
+----------+---------------------+-------------+-------------+
| 1 | 2020-01-11 00:00:00 | 2 | 157.8 |
+----------+---------------------+-------------+-------------+
1 row in set (0.00 sec)
次に、からレコードを取得します orders_products
テーブル:
- SELECT * FROM orders_products;
顧客の注文からの製品のリストとともに、次のような出力が表示されます。
Output+--------+----------+------------+-------+----------+
| ref_id | order_id | product_id | price | quantity |
+--------+----------+------------+-------+----------+
| 1 | 1 | 1 | 25.5 | 1 |
| 2 | 1 | 2 | 13.9 | 3 |
| 3 | 1 | 3 | 45.3 | 2 |
+--------+----------+------------+-------+----------+
3 rows in set (0.00 sec)
出力は、トランザクションがデータベースとヘルパーに保存されたことを確認します DBTransaction
クラスは期待どおりに機能しています。
結論
このガイドでは、PHPPDOを使用してMySQLトランザクションを処理しました。 これはeコマースソフトウェアの設計に関する決定的な記事ではありませんが、アプリケーションでMySQLトランザクションを使用するための例を提供しています。
MySQL ACIDモデルの詳細については、MySQLの公式WebサイトからInnoDBおよびACIDモデルガイドにアクセスすることを検討してください。 私たちをご覧ください MySQLコンテンツページ関連するチュートリアル、記事、およびQ&Aについては。