この質問はかなり古いものですが、OPと同じことを研究している他の人のためにここで概説する必要があるいくつかのトピックは実際には議論されていません.
以下のすべてを要約すると:
- はい、常に準備ステートメントを使用します
- はい、mysql ではなく mysqli で PDO を使用します。このようにデータベース システムを切り替えた場合、クエリ、関数呼び出し、引数の代わりにクエリを更新するだけで、準備済みステートメントがサポートされます。
- パラメータ付きの準備済みステートメントを使用している場合でも、ユーザーが提供したデータを常にサニタイズします
- DBAL (データベース アブストラクション レイヤー) を調べて、これらすべての要素を簡単に処理し、ニーズに合わせてクエリを操作してください。
PDO::ATTR_EMULATE_PREPARES のトピックがあります。これにより、MySQL >= 5.1.21 でキャッシュされたクエリを呼び出すパフォーマンスが向上します。つまり、PHP は実行前に準備をエミュレートし、実際のデータベースに送信します。エミュレートされてからエミュレートされないまでの時間は、異常に高い ping レートを持つ可能性があるクラウドなどの外部データベース (localhost ではない) を使用しない限り、通常は無視できます。
キャッシュは my.cnf の MySQL 設定にも依存しますが、MySQL の最適化はこの投稿の範囲外です。
<?php
$pdo = new \PDO($connection_string);
$pdo->setAttribute( \PDO::ATTR_EMULATE_PREPARES, false );
?>
mysqli_ はクライアント側のエミュレーション用の API を提供せず、ステートメントの準備に常に MySQL を使用するため、この点に注意してください。
http://www.php.net/manual/en/mysqli.quickstart.prepared-statements.php
類似した機能があっても違いがあり、ある API が提供する機能が必要で、他の API が提供しない機能が必要になる場合があります。API の選択に関する PHP のリファレンスを参照してください: http://www.php.net/manual/en/mysqlinfo.api.choosing.php
したがって、これは、キャッシュ可能なクエリが MySQL サーバーにキャッシュされ、アプリケーション全体で準備する必要がないため、アプリケーション全体でステートメントを定義する際に求めたこととほぼ一致します。もう 1 つの利点は、クエリの例外が execute() ではなく prepare() でスローされることです。これは、クエリが正しいことを確認するための開発を支援します。
準備を使用するかどうかに関係なく、実際のパフォーマンス上の利点はありません。
プリペアド ステートメントのもう 1 つの利点は、InnoDB for MySQL を使用している場合にトランザクションを操作できることです。トランザクションを開始し、レコードを挿入し、最後の挿入 ID を取得し、別のテーブルを更新し、別のテーブルから削除できます。途中で何かが失敗した場合は、トランザクションが発生する前に rollBack() できます。それ以外の場合は、変更をコミットします。たとえば、新しい注文を処理し、ユーザーの最後の注文列を新しい注文 ID に設定し、保留中の注文を削除しますが、指定された支払いの種類が order_flags テーブルから注文を出すための基準を満たしていないため、rollBack() を実行できます。ユーザーに分かりやすいエラー メッセージを表示します。
セキュリティに関しては、誰もこれに触れていないことにかなり困惑しています。ユーザーが提供したデータを PHP や MySQL を含む任意のシステムに送信する場合は、サニタイズして標準化してください。はい、準備されたステートメントは、データのエスケープに関してある程度のセキュリティを提供しますが、100% の防弾ではありません。
そのため、常にプリペアド ステートメントを使用することは、実際のパフォーマンスの低下がない場合よりもはるかに有益であり、キャッシュにはいくつかの利点がありますが、それでもユーザーが提供したデータをサニタイズする必要があります。1 つのステップは、変数を作業中の目的のデータ型に型キャストすることです。オブジェクトを使用すると、同じデータを操作するたびに記憶する必要がなく、データ型の単一のモデル内で作業するため、これがさらに容易になります。
上記に追加するには、PDO を使用するデータベース抽象化レイヤーを調べる必要があります。たとえばDoctrine DBAL: http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/query-builder.html
DBAL+PDO を使用することの追加の利点は、次のとおりです。
- やるべき仕事の量を標準化し、短縮することができます。
- ユーザー提供データのサニタイズを支援
- 複雑なクエリを簡単に操作
- ネストされたトランザクションを使用する
- データベースを簡単に切り替える
- コードの移植性が高まり、他のプロジェクトで使用できるようになります
たとえば、PDO を拡張し、query()、fetchAll()、および fetch() メソッドをオーバーライドして、これらのメソッドが常に準備済みステートメントを使用するようにし、SQL ステートメントを fetch() または fetchAll() 内に記述する代わりに記述できるようにしました。すべてをもう一度。例えば:
<?php
$pdo = new PDOEnhanced( $connection );
$pdo->fetchAll( "SELECT * FROM foo WHERE bar = 'hi'", PDO::FETCH_OBJ );
//would automatically provide
$stmt = $pdo->prepare( "SELECT * FROM foo WHERE bar=?" );
$stmt->execute( array( 'hi' ) );
$resultSet = $stmt->fetchAll( PDO::FETCH_OBJ )
?>
その mysql_* スタイルを提案する人々に関しては、mysqli_* API に置き換えるだけの方がはるかに簡単です。そうではありません。mysql_* 関数の大部分が除外されたか、mysqli_* で引数が変更されました。参照: http://php.net/manual/en/mysqli.summary.php
ただし、プロセスを容易にするために Oracle からリリースされたコンバーターを入手できます: https://wikis.oracle.com/display/mysql/Converting+to+MySQLi
これはファイル ソース テキスト パーサーであり、100% 正確ではないことに注意してください。変更をマージする前に検証してください。また、作成するグローバルにかなりの量のオーバーヘッドが追加されます。