Query query = em.createNativeQuery("SELECT * FROM t_customer", Customer.class);
List
Как вы можете видеть в приведенном фрагменте кода, SQL-запрос является строкой, которая динамически генерируется во время выполнения (точно так же, как динамические JPQL-запросы). Опять-таки запрос может быть комплексным, и, поскольку поставщик не будет заранее знать о нем, он станет каждый раз интерпретировать его. Подобно именованным запросам, «родные» могут задействовать аннотации для определения статических SQL-запросов. Именованные «родные» запросы определяются с помощью аннотации @NamedNativeQuery, которую необходимо поместить в код любой сущности (см. код ниже). Как и в случае с именованными JPQL-запросами, имя запроса должно быть уникальным в единице сохраняемости.
@Entity
@NamedNativeQuery(name = "findAll", query="select * from t_customer")
@Table(name = "t_customer")
public class Customer {…}
Запросы к хранимым процедурам
До сих пор у всех разных запросов (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.
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 в нашем примере) используются при выполнении хранимой процедуры, которая, в свою очередь, может генерировать выходной результат. Этот результат возвращается приложению при использовании результирующего набора.