Query query = em.createNativeQuery("SELECT * FROM t_customer", Customer.class);

List customers = query.getResultList();

Как вы можете видеть в приведенном фрагменте кода, SQL-запрос является строкой, которая динамически генерируется во время выполнения (точно так же, как динамические JPQL-запросы). Опять-таки запрос может быть комплексным, и, поскольку поставщик не будет заранее знать о нем, он станет каждый раз интерпретировать его. Подобно именованным запросам, «родные» могут задействовать аннотации для определения статических SQL-запросов. Именованные «родные» запросы определяются с помощью аннотации @NamedNativeQuery, которую необходимо поместить в код любой сущности (см. код ниже). Как и в случае с именованными JPQL-запросами, имя запроса должно быть уникальным в единице сохраняемости.

@Entity

@NamedNativeQuery(name = "findAll", query="select * from t_customer")

@Table(name = "t_customer")

public class Customer {…}

<p>Запросы к хранимым процедурам</p>

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

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

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

• Сохранение статистики, касающейся кода, для поддержания его оптимизированным.

• Снижение количества данных, передаваемых по сети, благодаря сохранению кода на сервере.

• Изменение кода в центральной локации без репликации в нескольких разных программах.

• Хранимые процедуры, которые могут использоваться множеством программ, написанных на разных языках (а не только на Java).

• Скрытие необработанных данных путем предоставления доступа к информации только хранимым процедурам.

• Усиление мер безопасности путем предоставления пользователем разрешения на выполнение той или иной хранимой процедуры независимо от разрешений, связанных с базовой таблицей.

Взглянем на пример из практики — архивирование старых книг и компакт-дисков. После определенной даты книги и компакт-диски должны помещаться в архив на конкретном складе, а это означает, что затем их придется физически перевозить со склада к перекупщику. Архивирование книг и компакт-дисков может отнимать много времени, поскольку потребуется обновлять несколько таблиц (с именами, например, T_Inventory, T_Warehouse, T_Book, T_CD, T_Transport и т. д.). Таким образом, мы можем написать хранимую процедуру для перегруппировки нескольких SQL-операторов и повышения производительности. Хранимая процедура sp_archive_books, определенная в листинге 6.29, принимает archiveDate и warehouseCode в качестве параметров и обновляет таблицы T_Inventory и T_Transport.

Листинг 6.29. Абстракция хранимой процедуры, используемой при архивировании книг

CREATE PROCEDURE sp_archive_books @archiveDate DATE, @warehouseCode VARCHAR AS

··UPDATE T_Inventory

··SET Number_Of_Books_Left — 1

··WHERE Archive_Date < @archiveDate AND Warehouse_Code = @warehouseCode;

··UPDATE T_Transport

··SET Warehouse_To_Take_Books_From = @warehouseCode;

END

Хранимая процедура из листинга 6.29 помещается в базу данных, а затем может вызываться по своему имени (sp_archive_books). Как вы можете видеть, хранимая процедура принимает данные в виде входных или выходных параметров. Входные параметры (@archiveDate и @warehouseCode в нашем примере) используются при выполнении хранимой процедуры, которая, в свою очередь, может генерировать выходной результат. Этот результат возвращается приложению при использовании результирующего набора.

Перейти на страницу:

Похожие книги