ステートメントとPreparedStatementの違い

Javaトップ

Spring5とSpringBoot2の基礎に焦点を当てた新しいLearnSpringコースを発表しました。

>>コースをチェックしてください

1。概要

このチュートリアルでは、JDBCのStatementインターフェースとPreparedStatementインターフェースの違いについて説明します。ストアドプロシージャの実行に使用されるJDBCAPIインターフェイスであるCallableStatementについては説明しません。

2. JDBCAPIインターフェース

StatementPreparedStatementの両方を使用して、SQLクエリを実行できます。これらのインターフェイスは非常によく似ています。ただし、機能とパフォーマンスは互いに大きく異なります。

  • ステートメント文字列ベースのSQLクエリを実行するために使用されます
  • PreparedStatementパラメーター化されたSQLクエリを実行するために使用されます

使用できるようにするために声明PreparedStatementを私たちの例では、私たちは宣言しますh2は私たちの中に依存関係としてJDBCコネクタのpom.xmlのファイルを:

 com.h2database h2 1.4.200 

この記事全体で使用するエンティティを定義しましょう。

public class PersonEntity { private int id; private String name; // standard setters and getters }

3.ステートメント

まず、StatementインターフェイスはSQLクエリとして文字列を受け入れます。したがって、SQL文字列を連結すると、コードが読みにくくなります。

public void insert(PersonEntity personEntity) { String query = "INSERT INTO persons(id, name) VALUES(" + personEntity.getId() + ", '" + personEntity.getName() + "')"; Statement statement = connection.createStatement(); statement.executeUpdate(query); }

第二に、SQLインジェクションに対して脆弱です。次の例は、この弱点を示しています。

最初の行で、更新により、すべての行の列「name」が「hacker」に設定されます。「—」の後はSQLでコメントとして解釈され、更新ステートメントの条件は無視されます。2行目では、「name」列の引用符がエスケープされていないため、挿入は失敗します。

dao.update(new PersonEntity(1, "hacker' --")); dao.insert(new PersonEntity(1, "O'Brien"))

第3に、JDBCはインライン値を含むクエリをデータベースに渡します。したがって、クエリの最適化はありません。最も重要なことは、データベースエンジンがすべてのチェックを確実にする必要があることです。また、クエリはデータベースに同じようには表示されず、キャッシュの使用を防ぎます。同様に、バッチ更新は個別に実行する必要があります。

public void insert(List personEntities) { for (PersonEntity personEntity: personEntities) { insert(personEntity); } }

第4にStatementインターフェースは、CREATE、ALTER、DROPなどのDDLクエリに適しています

public void createTables() { String query = "create table if not exists PERSONS (ID INT, NAME VARCHAR(45))"; connection.createStatement().executeUpdate(query); }

最後にStatementインターフェイスは、ファイルと配列の保存と取得には使用できません

4.プリペアドステートメント

まず、PreparedStatementStatementインターフェースを拡張します。ファイルや配列など、さまざまなオブジェクトタイプをバインドするメソッドがあります。したがって、コードは理解しやすくなります

public void insert(PersonEntity personEntity) { String query = "INSERT INTO persons(id, name) VALUES( ?, ?)"; PreparedStatement preparedStatement = connection.prepareStatement(query); preparedStatement.setInt(1, personEntity.getId()); preparedStatement.setString(2, personEntity.getName()); preparedStatement.executeUpdate(); }

次に、提供されたすべてのパラメーター値のテキストをエスケープすることにより、SQLインジェクションから保護します

@Test void whenInsertAPersonWithQuoteInText_thenItNeverThrowsAnException() { assertDoesNotThrow(() -> dao.insert(new PersonEntity(1, "O'Brien"))); } @Test void whenAHackerUpdateAPerson_thenItUpdatesTheTargetedPerson() throws SQLException { dao.insert(Arrays.asList(new PersonEntity(1, "john"), new PersonEntity(2, "skeet"))); dao.update(new PersonEntity(1, "hacker' --")); List result = dao.getAll(); assertEquals(Arrays.asList( new PersonEntity(1, "hacker' --"), new PersonEntity(2, "skeet")), result); }

第三に、PreparedStatementはプリコンパイルを使用します。データベースはクエリを取得するとすぐに、クエリをプリコンパイルする前にキャッシュをチェックします。したがって、キャッシュされていない場合、データベースエンジンは次の使用のためにそれを保存します。

さらに、この機能は、 SQL以外のバイナリプロトコルを介したデータベースとJVM間の通信を高速化します。つまり、パケット内のデータが少ないため、サーバー間の通信が高速になります。

第4に、PreparedStatementは、単一のデータベース接続中にバッチ実行を提供します。これを実際に見てみましょう:

public void insert(List personEntities) throws SQLException { String query = "INSERT INTO persons(id, name) VALUES( ?, ?)"; PreparedStatement preparedStatement = connection.prepareStatement(query); for (PersonEntity personEntity: personEntities) { preparedStatement.setInt(1, personEntity.getId()); preparedStatement.setString(2, personEntity.getName()); preparedStatement.addBatch(); } preparedStatement.executeBatch(); }

次に、PreparedStatementは、BLOBおよびCLOBデータ型を使用してファイルを格納および取得する簡単な方法を提供します。同様に、java.sql.ArrayをSQL配列に変換することにより、リストを格納するのに役立ちます。

最後に、PreparedStatementは、返された結果に関する情報を含むgetMetadata()のようなメソッドを実装します。

5。結論

このチュートリアルでは、PreparedStatementStatementの主な違いを紹介しました。どちらのインターフェースもSQLクエリを実行するメソッドを提供しますが、DDLクエリにはStatementを使用し、DMLクエリにはPreparedStatementを使用する方が適しています。

いつものように、すべてのコード例はGitHubで入手できます。

Javaの底

Spring5とSpringBoot2の基礎に焦点を当てた新しいLearnSpringコースを発表しました。

>>コースをチェックしてください