PHPでは、データベース操作にMySQLI拡張機能を使用する場合、 MySQLI_STMT :: PREPAREは、前処理ステートメントの重要な方法です。 SQL注入を効果的に防止し、実行効率を改善できます。ただし、トランザクション処理では、 mysqli_stmt :: prepareを使用する場合、しばしばいくつかの落とし穴に遭遇します。この記事では、これらの一般的な落とし穴を詳細に分析し、対応するソリューションを提供します。
トランザクションは、データベース管理の一連の操作であり、これらの操作が成功するか、すべて失敗する必要があります。 MySQLIのトランザクションコントロールを使用して、次の方法は通常呼び出されます。
$mysqli->begin_transaction();
$mysqli->commit();
$mysqli->rollback();
mysqli_stmt :: SQLステートメントとプレキサマイズを準備します。 SQLステートメントが合法であり、バインドされたパラメーターが正しいことを確認するために正しく使用されます。
ピットポイント: $ stmt = $ mysqli-> prepare($ sql);を呼び出した後、 $ stmtがfalseかどうかは確認されません。 SQLの構文エラーまたはその他の理由の場合、準備が失敗した場合、トランザクションは実行され続け、その後の操作はエラーを報告し、トランザクションの例外になります。
解決する:
$stmt = $mysqli->prepare($sql);
if ($stmt === false) {
$mysqli->rollback();
throw new Exception('Prepare failed: ' . $mysqli->error);
}
トランザクションでは、準備が失敗した場合、ロールバックして後続の操作を停止します。
ポイント:開発者が$ stmt = $ mysqli-> prepare($ sql)を実行する場合があります。 $ mysqli-> begin_transaction() ;を呼び出す前に。ただし、特定のMySQLバージョンまたは構成では、前処理ステートメントが自動的に暗黙的にコミットされるため、トランザクション効果が無効になります。
解決する:
最初にトランザクションを開始してから、準備を実行してください。
$mysqli->begin_transaction();
$stmt = $mysqli->prepare($sql);
// その後のバインディングと実行
ポイント:プリプロセシングステートメントは、複数のSQLステートメントの記述を一度にサポートしていません。 $ sqlがセミコロンによって分割された複数のステートメントが含まれている場合、準備は失敗します。
解決する:
各SQLステートメントのみを準備し、必要に応じて複数のステートメントを個別に実行することを確認してください。
ピットポイント:タイプのミスマッチやバインドされていないすべてのプレースホルダーなどのパラメーターバインディングエラーは、実行障害を引き起こし、トランザクションは最終的に失敗します。
解決する:
次のような、バインドされたパラメーターのタイプと数が正しいことを確認してください。
$stmt->bind_param('si', $name, $id);
bind_paramの返品値を確認します。
ピットポイント: $ stmt-> close()がトランザクションが終了する前に呼び出されない場合、接続リソースがリリースされず、その後のトランザクション操作に影響を与える可能性があります。
解決する:
トランザクションが終了する前に、 $ stmt-> close()を呼び出して、リソースが時間内にリリースされるようにします。
ピットポイント:猛攻撃の例外またはエラーが発生し、トランザクションが適切にコミットされたり、ロールバックされたりしません。
解決する:
トライキャッチ構造を使用して、例外をキャッチするときにトランザクションをロールバックします。
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();
}
<?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();
?>
トランザクションが開始されたら、常に準備してください。
prepere 、 bind_param 、および実行の返品値を確認します。
各準備は単一のステートメントのみを処理します。
例外が発生したら、必ずトランザクションをロールバックしてください。
プリプロセシングステートメントリソースを閉じます。
上記の仕様に従って、 MySQLI_STMT ::トランザクション処理の準備、データの一貫性とコードの堅牢性を確保する際に遭遇する一般的な落とし穴を効果的に回避できます。