トランザクションを実行する方法
SQL Server Driver for PHP には、トランザクションを実行するための関数が 3 つ用意されています。
このトピックでは、これらの関数を使用してトランザクションを実行する方法について説明します。
トランザクションを実行する手順は、次のようにまとめることができます。
- トランザクションの一部であるすべてのクエリの前に、sqlsrv_begin_transaction を記述します。
- トランザクションの一部である各クエリの成功または失敗を調べます。
- 適切な場合は、sqlsrv_commit を使用してトランザクションをコミットします。それ以外の場合は、sqlsrv_rollback を使用してトランザクションをロールバックします。sqlsrv_commit または sqlsrv_rollback を呼び出した後、ドライバは自動コミット モードに戻ります。
注意
SQL Server Driver for PHP は、既定で自動コミット モードになっています。つまり、sqlsrv_begin_transaction を使用して明示的トランザクションの一部として指定しない限り、すべてのクエリが、成功時に自動的にコミットされます。
注意
明示的トランザクションが sqlsrv_commit によってコミットされない場合は、接続を閉じるときか、またはスクリプトを終了するときに、トランザクションがロールバックされます。
注意
トランザクションの実行に埋め込み Transact-SQL を使用しないでください。たとえば、トランザクションを開始するために、"BEGIN TRANSACTION" を使用するステートメントを Transact-SQL クエリとして実行しないでください。埋め込み Transact-SQL を使用してトランザクションを実行した場合、予期したとおりにトランザクションが動作する保証がありません。
トランザクションを実行するには、既に示した sqlsrv 関数を使用する必要があります。例
次の例では、複数のクエリをトランザクションの一部として実行します。すべてのクエリが成功した場合、トランザクションはコミットされます。いずれかのクエリが失敗した場合、トランザクションはロールバックされます。
この例では、Sales.SalesOrderDetail テーブルから販売注文を削除し、その販売注文内の各製品について Product.ProductInventory テーブルで製品在庫レベルを調整します。これらのクエリを 1 つのトランザクションに含めているのは、注文の状態と製品の入手可能性をデータベースに正確に反映させるには、すべてのクエリが成功する必要があるためです。
この例の最初のクエリは、指定された販売注文 ID についての製品 ID と数量を取得します。このクエリは、トランザクションの一部ではありません。しかし、このクエリが失敗した場合、スクリプトは終了します。これは、以降のトランザクションの一部であるクエリを完了するには、製品 ID と数量が必要になるためです。
保証対象のクエリ (販売注文の削除と、製品在庫数量の更新) は、トランザクションの一部です。
この例では、SQL Server と AdventureWorks データベースがローカル コンピュータにインストールされていることを前提としています。この例をコマンド ラインから実行した場合、すべての出力はコンソールに書き込まれます。
<?php
/* Connect to the local server using Windows Authentication and
specify the AdventureWorks database as the database in use. */
$serverName = "(local)";
$connectionInfo = array( "Database"=>"AdventureWorks");
$conn = sqlsrv_connect( $serverName, $connectionInfo);
if( $conn === false )
{
echo "Could not connect.\n";
die( print_r( sqlsrv_errors(), true));
}
/* Begin transaction. */
if( sqlsrv_begin_transaction($conn) === false )
{
echo "Could not begin transaction.\n";
die( print_r( sqlsrv_errors(), true));
}
/* Set the Order ID. */
$orderId = 43667;
/* Execute operations that are part of the transaction. Commit on
success, roll back on failure. */
if (perform_trans_ops($conn, $orderId))
{
//If commit fails, roll back the transaction.
if(sqlsrv_commit($conn))
{
echo "Transaction committed.\n";
}
else
{
echo "Commit failed - rolling back.\n";
sqlsrv_rollback($conn);
}
}
else
{
"Error in transaction operation - rolling back.\n";
sqlsrv_rollback($conn);
}
/*Free connection resources*/
sqlsrv_close( $conn);
/*---------------- FUNCTION: perform_trans_ops -----------------*/
function perform_trans_ops($conn, $orderId)
{
/* Define query to update inventory based on sales order info. */
$tsql1 = "UPDATE Production.ProductInventory
SET Quantity = Quantity + s.OrderQty
FROM Production.ProductInventory p
JOIN Sales.SalesOrderDetail s
ON s.ProductID = p.ProductID
WHERE s.SalesOrderID = ?";
/* Define the parameters array. */
$params = array($orderId);
/* Execute the UPDATE statement. Return false on failure. */
if( sqlsrv_query( $conn, $tsql1, $params) === false ) return false;
/* Delete the sales order. Return false on failure */
$tsql2 = "DELETE FROM Sales.SalesOrderDetail
WHERE SalesOrderID = ?";
if(sqlsrv_query( $conn, $tsql2, $params) === false ) return false;
/* Return true because all operations were successful. */
return true;
}
?>
上の例では、トランザクション動作に焦点を当てるため、推奨されるエラー処理を含めていません。実稼働のアプリケーションでは、sqlsrv 関数のすべての呼び出しにエラーがないかどうかを確認し、適切に処理することをお勧めします。