現在の位置: ホーム> 最新記事一覧> mysqli_stmt ::トランザクションで一般的な落とし穴を準備します

mysqli_stmt ::トランザクションで一般的な落とし穴を準備します

gitbox 2025-05-29

PHPでは、データベース操作にMySQLI拡張機能を使用する場合、 MySQLI_STMT :: PREPAREは、前処理ステートメントの重要な方法です。 SQL注入を効果的に防止し、実行効率を改善できます。ただし、トランザクション処理では、 mysqli_stmt :: prepareを使用する場合、しばしばいくつかの落とし穴に遭遇します。この記事では、これらの一般的な落とし穴を詳細に分析し、対応するソリューションを提供します。

1.トランザクションと前処理ステートメントの基本的な関係

トランザクションは、データベース管理の一連の操作であり、これらの操作が成功するか、すべて失敗する必要があります。 MySQLIのトランザクションコントロールを使用して、次の方法は通常呼び出されます。

 $mysqli->begin_transaction();
$mysqli->commit();
$mysqli->rollback();

mysqli_stmt :: SQLステートメントとプレキサマイズを準備します。 SQLステートメントが合法であり、バインドされたパラメーターが正しいことを確認するために正しく使用されます。

2。一般的な落とし穴と解決策

1.結果を準備してください。前処理ステートメントでチェックされていません

ピットポイント$ stmt = $ mysqli-> prepare($ sql);を呼び出した後、 $ stmtfalseかどうかは確認されません。 SQLの構文エラーまたはその他の理由の場合、準備が失敗した場合、トランザクションは実行され続け、その後の操作はエラーを報告し、トランザクションの例外になります。

解決する

 $stmt = $mysqli->prepare($sql);
if ($stmt === false) {
    $mysqli->rollback();
    throw new Exception('Prepare failed: ' . $mysqli->error);
}

トランザクションでは、準備が失敗した場合、ロールバックして後続の操作を停止します。

2。トランザクションが開始される前に準備が実行されました

ポイント:開発者が$ stmt = $ mysqli-> prepare($ sql)を実行する場合があります。 $ mysqli-> begin_transaction() ;を呼び出す前に。ただし、特定のMySQLバージョンまたは構成では、前処理ステートメントが自動的に暗黙的にコミットされるため、トランザクション効果が無効になります。

解決する

最初にトランザクションを開始してから、準備を実行してください。

 $mysqli->begin_transaction();
$stmt = $mysqli->prepare($sql);
// その後のバインディングと実行

3.複数のSQLステートメントを使用する場合、分離しないでください

ポイント:プリプロセシングステートメントは、複数のSQLステートメントの記述を一度にサポートしていません。 $ sqlがセミコロンによって分割された複数のステートメントが含まれている場合、準備は失敗します。

解決する

各SQLステートメントのみを準備し、必要に応じて複数のステートメントを個別に実行することを確認してください。

4.パラメーターを正しくバインドしないと、データの例外が発生します

ピットポイント:タイプのミスマッチやバインドされていないすべてのプレースホルダーなどのパラメーターバインディングエラーは、実行障害を引き起こし、トランザクションは最終的に失敗します。

解決する

次のような、バインドされたパラメーターのタイプと数が正しいことを確認してください。

 $stmt->bind_param('si', $name, $id);

bind_paramの返品値を確認します。

5.プリプロセシングステートメントを閉じるのを忘れました

ピットポイント$ stmt-> close()がトランザクションが終了する前に呼び出されない場合、接続リソースがリリースされず、その後のトランザクション操作に影響を与える可能性があります。

解決する

トランザクションが終了する前に、 $ stmt-> close()を呼び出して、リソースが時間内にリリースされるようにします。

6.エラー処理と例外キャッチングを無視します

ピットポイント:猛攻撃の例外またはエラーが発生し、トランザクションが適切にコミットされたり、ロールバックされたりしません。

解決する

トライキャッチ構造を使用して、例外をキャッチするときにトランザクションをロールバックします。

 try {
    $mysqli->begin_transaction();

    $stmt = $mysqli->prepare($sql);
    if ($stmt === false) {
        throw new Exception($mysqli->error);
    }

    $stmt->bind_param('si', $name, $id);
    $stmt->execute();

    $mysqli->commit();
} catch (Exception $e) {
    $mysqli->rollback();
    echo "Transaction failed: " . $e->getMessage();
}

3.完全な例

<?php
$mysqli = new mysqli('gitbox.net', 'user', 'password', 'database');
if ($mysqli->connect_error) {
    die('Connect Error (' . $mysqli->connect_errno . ') ' . $mysqli->connect_error);
}

try {
    $mysqli->begin_transaction();

    $sql = "UPDATE users SET name = ? WHERE id = ?";
    $stmt = $mysqli->prepare($sql);
    if ($stmt === false) {
        throw new Exception('Prepare failed: ' . $mysqli->error);
    }

    $name = 'Alice';
    $id = 123;
    if (!$stmt->bind_param('si', $name, $id)) {
        throw new Exception('Bind param failed: ' . $stmt->error);
    }

    if (!$stmt->execute()) {
        throw new Exception('Execute failed: ' . $stmt->error);
    }

    $stmt->close();

    $mysqli->commit();
    echo "Transaction succeeded.";
} catch (Exception $e) {
    $mysqli->rollback();
    echo "Transaction failed: " . $e->getMessage();
}

$mysqli->close();
?>

4。概要

  • トランザクションが開始されたら、常に準備してください

  • preperebind_param 、および実行の返品値を確認します。

  • 準備は単一のステートメントのみを処理します。

  • 例外が発生したら、必ずトランザクションをロールバックしてください。

  • プリプロセシングステートメントリソースを閉じます。

上記の仕様に従って、 MySQLI_STMT ::トランザクション処理の準備、データの一貫性とコードの堅牢性を確保する際に遭遇する一般的な落とし穴を効果的に回避できます。