Hibernateを使ったストアドプロシージャ

Hibernateでのストアドプロシージャ

1. 概要

ストアドプロシージャは、コンパイルされたSQLステートメントのセットですresiding in the database.ロジックをカプセル化し、他のプログラムと共有するために使用され、インデックスヒントや特定のキーワードなどのデータベース固有の機能を利用できます。

この記事では、Hibernateを使用してMySQL database内のstored procedureを呼び出す方法を示します。

2. MySQLのストアドプロシージャ

Hibernateからストアドプロシージャを呼び出す方法を説明する前に、作成する必要があります。

この簡単なMySQLの例では、create a stored procedureを使用して、fooテーブルからすべてのレコードを取得します。

ストアドプロシージャを作成するには、CREATE PROCEDUREステートメントを使用します。

DELIMITER //
    CREATE PROCEDURE GetAllFoos()
        LANGUAGE SQL
        DETERMINISTIC
        SQL SECURITY DEFINER
        BEGIN
            SELECT * FROM foo;
        END //
DELIMITER;

BEGINステートメントの前に、オプションのステートメントを定義できます。 公式のMySQL documentationリンクをたどると、これらのステートメントの詳細にドリルダウンできます。

CALLステートメントを使用して、プロシージャが目的の方法で動作することを確認できます。

CALL GetAllFoos();

ストアドプロシージャが稼働しているので、Hibernateから呼び出す方法に直接ジャンプしましょう。

3. Hibernateでストアドプロシージャを呼び出す

Hibernate 3からは、ストアドプロシージャを含む生のSQLステートメントを使用してデータベースにクエリを実行できるようになりました。

このセクションでは、Hibernateを使用してGetAllFoos()プロシージャを呼び出す方法を説明する、一見基本的な例について説明します。

3.1. 設定

実行可能なコードの記述を開始する前に、プロジェクトでHibernateを構成する必要があります。

そしてもちろん、Mavenの依存関係、MySQL構成、Hibernate構成、SessionFactoryのインスタンス化など、そのすべてについて、Hibernate articleを確認できます。

3.2. CreateNativeSQLメソッドを使用してストアドプロシージャを呼び出す

Hibernateを使用すると、クエリをnative SQL形式で直接表現できます。 したがって、ネイティブSQLクエリを簡単に作成し、CALLステートメントを使用してgetAllFoos()ストアドプロシージャを呼び出すことができます。

Query query = session.createSQLQuery("CALL GetAllFoos()").addEntity(Foo.class);
List allFoos = query.list();

上記のクエリは、各要素がFoo objectであるリストを返します。

addEntity()メソッドを使用して、ネイティブのSQLクエリからエンティティオブジェクトを取得します。そうしないと、ストアドプロシージャが生以外の値を返すたびにClassCastExceptionがスローされます。

3.3. @NamedNativeQueriesを使用してストアドプロシージャを呼び出す

ストアドプロシージャを呼び出す別の方法は、@NamedNativeQueriesアノテーションを使用することです。

@NamedNativeQueriesは、クエリscoped to the persistence unit:という名前のネイティブSQLの配列を指定するために使用されます

@NamedNativeQueries({
  @NamedNativeQuery(
    name = "callGetAllFoos",
    query = "CALL GetAllFoos()",
    resultClass = Foo.class)
})
@Entity
public class Foo implements Serializable {
    // Model definition
}

名前付きクエリにはそれぞれ、明らかにname属性、実際のSQL query、およびFooマップエンティティを参照するresultClassがあります。

Query query = session.getNamedQuery("callGetAllFoos");
List allFoos = query.list();

resultClass属性は、前の例のaddEntity()メソッドと同じ役割を果たします。

パフォーマンスと生産性に関しては両者の間に実際の違いはないため、これらのアプローチはどちらも同じ意味で使用できます。

3.4. @NamedStoredProcedureQueryを使用してストアドプロシージャを呼び出す

JPA 2.1EntityManagerFactoryおよびEntityManagerHibernate実装を使用している場合。

@NamedStoredProcedureQueryアノテーションを使用して、ストアドプロシージャを宣言できます。

@NamedStoredProcedureQuery(
  name="GetAllFoos",
  procedureName="GetAllFoos",
  resultClasses = { Foo.class }
)
@Entity
public class Foo implements Serializable {
    // Model Definition
}

名前付きストアドプロシージャクエリを呼び出すには、EntityManager,をインスタンス化してから、createNamedStoredProcedureQuery()メソッドを呼び出してプロシージャ:を作成する必要があります。

StoredProcedureQuery spQuery =
  entityManager.createNamedStoredProcedureQuery("getAllFoos");

StoredProcedureQueryオブジェクトでexecute()メソッドを呼び出すことにより、Fooエンティティのリストを直接取得できます。

4. パラメータ付きのストアドプロシージャ

ほとんどすべてのストアドプロシージャにはパラメータが必要です。 このセクションでは、Hibernateのパラメーターを使用してストアドプロシージャを呼び出す方法を示します。

MySQLgetFoosByName()ストアドプロシージャを作成しましょう。

このプロシージャは、name属性がfooNameパラメータと一致するFooオブジェクトのリストを返します。

DELIMITER //
    CREATE PROCEDURE GetFoosByName(IN fooName VARCHAR(255))
        LANGUAGE SQL
        DETERMINISTIC
        SQL SECURITY DEFINER
        BEGIN
            SELECT * FROM foo WHERE name = fooName;
        END //
DELIMITER;

GetFoosByName()プロシージャを呼び出すために、名前付きパラメータを使用します。

Query query = session.createSQLQuery("CALL GetFoosByName(:fooName)")
  .addEntity(Foo.class)
  .setParameter("fooName","New Foo");

同様に、名前付きパラメーター:fooNameは、@NamedNativeQueryアノテーションとともに使用できます。

@NamedNativeQuery(
  name = "callGetFoosByName",
  query = "CALL GetFoosByName(:fooName)",
  resultClass = Foo.class
)

名前付きクエリは次のように呼び出されます。

Query query = session.getNamedQuery("callGetFoosByName")
  .setParameter("fooName","New Foo");

@NamedStoredProcedureQueryアノテーションを使用する場合、@StoredProcedureParameter annotationを使用してパラメーターを指定できます。

@NamedStoredProcedureQuery(
  name="GetFoosByName",
  procedureName="GetFoosByName",
  resultClasses = { Foo.class },
  parameters={
    @StoredProcedureParameter(name="fooName", type=String.class, mode=ParameterMode.IN)
  }
)

registerStoredProcedureParameter()メソッドを使用して、fooNameパラメーターを使用してストアドプロシージャを呼び出すことができます。

StoredProcedureQuery spQuery = entityManager.
  createNamedStoredProcedureQuery("GetFoosByName")
  .registerStoredProcedureParameter(
    "New Foo",
    String.class ,
    ParameterMode.IN
  );

5. 結論

この記事では、さまざまなアプローチを使用してhow to use Hibernate to call a stored procedure in a MySQL databaseを示しました。

not all RDBMS support stored proceduresについて言及する価値があります。

この記事で提供されている例は、リンクされているGitHub projectで確認できます。