«1. Обзор

Хранимые процедуры представляют собой наборы скомпилированных операторов SQL, находящихся в базе данных. Они используются для инкапсуляции и совместного использования логики с другими программами, а также извлекают выгоду из функций, специфичных для базы данных, таких как подсказки индекса или определенные ключевые слова.

В этой статье показано, как использовать Hibernate для вызова хранимой процедуры в базе данных MySQL.

2. Хранимые процедуры в MySQL

Прежде чем мы обсудим, как вызывать хранимую процедуру из Hibernate, нам нужно ее создать.

Для этого быстрого примера MySQL мы создадим хранимую процедуру для получения всех записей из таблицы foo.

Чтобы создать хранимую процедуру, мы используем оператор CREATE PROCEDURE:

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

Перед оператором BEGIN мы можем определить необязательные операторы. Вы можете углубиться в детали этих утверждений, перейдя по ссылке официальной документации MySQL.

Мы можем использовать оператор CALL, чтобы убедиться, что наша процедура ведет себя нужным образом:

CALL GetAllFoos();

Теперь, когда наша хранимая процедура запущена и работает, давайте сразу перейдем к тому, как вызывать ее из Hibernate.

3. Вызов хранимой процедуры с помощью Hibernate

Начиная с Hibernate 3, у нас есть возможность использовать необработанные операторы SQL, включая хранимые процедуры, для запросов к базе данных.

В этом разделе мы рассмотрим, казалось бы, простой пример, который иллюстрирует, как вызывать процедуру GetAllFoos() с помощью Hibernate.

3.1. Конфигурация

Прежде чем мы начнем писать код, который может работать, нам нужно настроить Hibernate в нашем проекте.

И, конечно же, все это — зависимости Maven, конфигурация MySQL, конфигурация Hibernate и создание экземпляра SessionFactory — вы можете прочитать в статье Hibernate.

3.2. Вызов хранимой процедуры с использованием метода CreateNativeSQL

Hibernate позволяет напрямую выражать запросы в собственном формате SQL. Таким образом, мы можем напрямую создать собственный SQL-запрос и использовать оператор CALL для вызова хранимой процедуры getAllFoos():

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

Приведенный выше запрос возвращает список, в котором каждый элемент является объектом Foo.

Мы используем метод addEntity() для получения объектов сущностей из собственного SQL-запроса, в противном случае будет генерироваться исключение ClassCastException всякий раз, когда хранимая процедура возвращает не необработанное значение.

3.3. Вызов хранимой процедуры с помощью @NamedNativeQueries

Другой способ вызвать хранимую процедуру — использовать аннотацию @NamedNativeQueries.

@NamedNativeQueries используется для указания массива собственных именованных запросов SQL, относящихся к единице персистентности:

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

Каждый именованный запрос, очевидно, имеет атрибут имени, фактический запрос SQL и класс результата, который ссылается на Foo отображаемая сущность.

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

Атрибут resultClass играет ту же роль, что и метод addEntity() в нашем предыдущем примере.

Оба этих подхода можно использовать взаимозаменяемо, так как между ними нет реальной разницы, когда речь идет о производительности или производительности.

3.4. Вызов хранимой процедуры с помощью @NamedStoredProcedureQuery

Если вы используете JPA 2.1 и реализацию EntityManagerFactory и EntityManager в Hibernate.

Аннотацию @NamedStoredProcedureQuery можно использовать для объявления хранимой процедуры:

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

Для вызова нашего запроса именованной хранимой процедуры нам нужно создать экземпляр EntityManager, а затем вызвать метод createNamedStoredProcedureQuery() для создания процедуры. :

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

Мы можем напрямую получить список сущностей Foo, вызвав метод execute() для объекта StoredProcedureQuery.

4. Хранимые процедуры с параметрами

Почти всем нашим хранимым процедурам требуются параметры. В этом разделе мы собираемся показать, как вызывать хранимую процедуру с параметрами из Hibernate.

Давайте создадим хранимую процедуру getFoosByName() в MySQL.

Эта процедура возвращает список объектов Foo, в которых атрибут name соответствует параметру fooName:

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(
  name="GetFoosByName",
  procedureName="GetFoosByName",
  resultClasses = { Foo.class },
  parameters={
    @StoredProcedureParameter(name="fooName", type=String.class, mode=ParameterMode.IN)
  }
)

При использовании аннотации @NamedStoredProcedureQuery мы можем указать параметры с помощью аннотации @StoredProcedureParameter:

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

Мы можем использовать метод registerStoredProcedureParameter() для вызова наша хранимая процедура с параметром fooName:

5. Заключение

В этой статье показано, как использовать Hibernate для вызова хранимой процедуры в базе данных MySQL, используя различные подходы.

Стоит отметить, что не все СУБД поддерживают хранимые процедуры.