Я пишу простое веб-приложение для вызова хранимой процедуры и получения некоторых данных. Это очень простое приложение, которое взаимодействует с клиентской базой данных. Мы передаем идентификатор сотрудника и идентификатор компании, и хранимая процедура вернет данные о сотруднике.
Веб-приложение не может обновлять / удалять данные и использует SQL Server.
Я развертываю свое веб-приложение в Jboss AS. Должен ли я использовать JPA для доступа к хранимой процедуре или CallableStatement
. Никаких преимуществ использования JPA в этом случае.
Также какой будет оператор sql для вызова этой хранимой процедуры. Я никогда раньше не использовал хранимые процедуры, и я борюсь с этим. Google не очень помог.
Вот хранимая процедура:
CREATE procedure getEmployeeDetails (@employeeId int, @companyId int)
as
begin
select firstName,
lastName,
gender,
address
from employee et
where et.employeeId = @employeeId
and et.companyId = @companyId
end
Обновить:
Для всех, у кого есть проблема с вызовом хранимой процедуры с использованием JPA .
Query query = em.createNativeQuery("{call getEmployeeDetails(?,?)}",
EmployeeDetails.class)
.setParameter(1, employeeId)
.setParameter(2, companyId);
List<EmployeeDetails> result = query.getResultList();
Я заметил:
- Имена параметров у меня не работали, поэтому попробуйте использовать индекс параметра.
- Правильный оператор sql
{call sp_name(?,?)}
вместоcall sp_name(?,?)
- Если хранимая процедура возвращает набор результатов, даже если вы знаете только одну строку, не
getSingleResult
будет работать - Передайте
resultSetMapping
имя или сведения о классе результата
Ответы:
JPA 2.1 теперь поддерживает хранимые процедуры, прочтите документ Java здесь .
Пример:
StoredProcedureQuery storedProcedure = em.createStoredProcedureQuery("sales_tax"); // set parameters storedProcedure.registerStoredProcedureParameter("subtotal", Double.class, ParameterMode.IN); storedProcedure.registerStoredProcedureParameter("tax", Double.class, ParameterMode.OUT); storedProcedure.setParameter("subtotal", 1f); // execute SP storedProcedure.execute(); // get result Double tax = (Double)storedProcedure.getOutputParameterValue("tax");
См. Подробный пример здесь .
источник
На самом деле это не поддерживается JPA, но это выполнимо . Тем не менее, я бы не пошел по этому пути:
Поэтому я бы предпочел использовать поддержку Spring для доступа к данным JDBC или средство отображения данных, такое как MyBatis, или, учитывая простоту вашего приложения, необработанные JDBC и
CallableStatement
. Собственно, я бы, наверное, выбрал JDBC. Вот базовый пример начала:CallableStatement cstmt = con.prepareCall("{call getEmployeeDetails(?, ?)}"); cstmt.setInt("employeeId", 123); cstmt.setInt("companyId", 456); ResultSet rs = cstmt.executeQuery();
Справка
источник
Вам необходимо передать параметры хранимой процедуре.
Это должно работать так:
List result = em .createNativeQuery("call getEmployeeDetails(:employeeId,:companyId)") .setParameter("emplyoyeeId", 123L) .setParameter("companyId", 456L) .getResultList();
Обновить:
А может и не должно.
В книге EJB3 в действии на странице 383 говорится, что JPA не поддерживает хранимые процедуры (страница - это только предварительный просмотр, вы не получаете полный текст, вся книга доступна для загрузки в нескольких местах, включая это , Я не знаю, законно ли это).
Во всяком случае, текст такой:
JPA и хранимые процедуры базы данных
источник
Как получить выходной параметр хранимой процедуры с помощью JPA (для версии 2.0 требуется импорт EclipseLink, а для версии 2.1 - нет)
Несмотря на то, что в этом ответе подробно рассказывается о возврате набора записей из хранимой процедуры, я публикую здесь, потому что мне потребовалось время, чтобы понять это, и этот поток мне помог.
В моем приложении использовался Eclipselink-2.3.1, но я принудительно обновлю его до Eclipselink-2.5.0, поскольку JPA 2.1 намного лучше поддерживает хранимые процедуры.
Использование EclipseLink-2.3.1 / JPA-2.0: зависит от реализации
Этот метод требует импорта классов EclipseLink из org.eclipse.persistence, поэтому он специфичен для реализации Eclipselink.
Я нашел его на http://www.yenlo.nl/en/calling-oracle-stored-procedures-from-eclipselink-with-multiple-out-parameters .
StoredProcedureCall storedProcedureCall = new StoredProcedureCall(); storedProcedureCall.setProcedureName("mypackage.myprocedure"); storedProcedureCall.addNamedArgument("i_input_1"); // Add input argument name. storedProcedureCall.addNamedOutputArgument("o_output_1"); // Add output parameter name. DataReadQuery query = new DataReadQuery(); query.setCall(storedProcedureCall); query.addArgument("i_input_1"); // Add input argument names (again); List<Object> argumentValues = new ArrayList<Object>(); argumentValues.add("valueOf_i_input_1"); // Add input argument values. JpaEntityManager jpaEntityManager = (JpaEntityManager) getEntityManager(); Session session = jpaEntityManager.getActiveSession(); List<?> results = (List<?>) session.executeQuery(query, argumentValues); DatabaseRecord record = (DatabaseRecord) results.get(0); String result = String.valueOf(record.get("o_output_1")); // Get output parameter
Использование EclipseLink-2.5.0 / JPA-2.1: Независимо от реализации (уже задокументировано в этом потоке)
Этот метод не зависит от реализации (импорт Eclipslink не требуется).
StoredProcedureQuery query = getEntityManager().createStoredProcedureQuery("mypackage.myprocedure"); query.registerStoredProcedureParameter("i_input_1", String.class, ParameterMode.IN); query.registerStoredProcedureParameter("o_output_1", String.class, ParameterMode.OUT); query.setParameter("i_input_1", "valueOf_i_input_1"); boolean queryResult = query.execute(); String result = String.valueOf(query.getOutputParameterValue("o_output_1"));
источник
xml
файле, и это не сработало. Я не могу прочитатьOUT
параметр.Для простой хранимой процедуры, использующей такие параметры IN / OUT
CREATE OR REPLACE PROCEDURE count_comments ( postId IN NUMBER, commentCount OUT NUMBER ) AS BEGIN SELECT COUNT(*) INTO commentCount FROM post_comment WHERE post_id = postId; END;
Вы можете вызвать его из JPA следующим образом:
StoredProcedureQuery query = entityManager .createStoredProcedureQuery("count_comments") .registerStoredProcedureParameter(1, Long.class, ParameterMode.IN) .registerStoredProcedureParameter(2, Long.class, ParameterMode.OUT) .setParameter(1, 1L); query.execute(); Long commentCount = (Long) query.getOutputParameterValue(2);
Для хранимой процедуры, которая использует
SYS_REFCURSOR
параметр OUT:CREATE OR REPLACE PROCEDURE post_comments ( postId IN NUMBER, postComments OUT SYS_REFCURSOR ) AS BEGIN OPEN postComments FOR SELECT * FROM post_comment WHERE post_id = postId; END;
Назвать его можно так:
StoredProcedureQuery query = entityManager .createStoredProcedureQuery("post_comments") .registerStoredProcedureParameter(1, Long.class, ParameterMode.IN) .registerStoredProcedureParameter(2, Class.class, ParameterMode.REF_CURSOR) .setParameter(1, 1L); query.execute(); List<Object[]> postComments = query.getResultList();
Для функции SQL, которая выглядит следующим образом:
CREATE OR REPLACE FUNCTION fn_count_comments ( postId IN NUMBER ) RETURN NUMBER IS commentCount NUMBER; BEGIN SELECT COUNT(*) INTO commentCount FROM post_comment WHERE post_id = postId; RETURN( commentCount ); END;
Вы можете назвать это так:
BigDecimal commentCount = (BigDecimal) entityManager .createNativeQuery( "SELECT fn_count_comments(:postId) FROM DUAL" ) .setParameter("postId", 1L) .getSingleResult();
По крайней мере, при использовании Hibernate 4.x и 5.x, потому что JPA
StoredProcedureQuery
не работает для ФУНКЦИЙ SQL.Дополнительные сведения о том, как вызывать хранимые процедуры и функции при использовании JPA и Hibernate, см. В следующих статьях.
источник
createNativeQuery
. Я перешел наcreateStoredProcedureQuery
. Тогда вуаля!Для меня с Oracle 11g и Glassfish 2.1 (Toplink) работало только следующее:
Query query = entityManager.createNativeQuery("BEGIN PROCEDURE_NAME(); END;"); query.executeUpdate();
Вариант с фигурными скобками привел к ORA-00900.
источник
При использовании EclipseLink вы можете использовать @NamedStoredProcedureQuery или StoreProcedureCall для выполнения любой хранимой процедуры, в том числе с выходными параметрами или курсорами. Также доступна поддержка хранимых функций и типов данных PLSQL.
См. Http://en.wikibooks.org/wiki/Java_Persistence/Advanced_Topics#Stored_Procedures
источник
Для меня работает следующее:
Query query = em.createNativeQuery("BEGIN VALIDACIONES_QPAI.RECALC_COMP_ASSEMBLY('X','X','X',0); END;"); query.executeUpdate();
источник
Может быть, это не то же самое для Sql Srver, но для людей, использующих oracle и eclipslink, он работает для меня
Пример: процедура с одним параметром IN (тип CHAR) и двумя параметрами OUT (NUMBER и VARCHAR)
в файле persistence.xml объявите единицу сохранения состояния:
<persistence-unit name="presistanceNameOfProc" transaction-type="RESOURCE_LOCAL"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <jta-data-source>jdbc/DataSourceName</jta-data-source> <mapping-file>META-INF/eclipselink-orm.xml</mapping-file> <properties> <property name="eclipselink.logging.level" value="FINEST"/> <property name="eclipselink.logging.logger" value="DefaultLogger"/> <property name="eclipselink.weaving" value="static"/> <property name="eclipselink.ddl.table-creation-suffix" value="JPA_STORED_PROC" /> </properties> </persistence-unit>
и объявите структуру процедуры в файле eclipselink-orm.xml
<?xml version="1.0" encoding="UTF-8"?><entity-mappings version="2.0" xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_2_0.xsd"> <named-stored-procedure-query name="PERSIST_PROC_NAME" procedure-name="name_of_proc" returns-result-set="false"> <parameter direction="IN" name="in_param_char" query-parameter="in_param_char" type="Character"/> <parameter direction="OUT" name="out_param_int" query-parameter="out_param_int" type="Integer"/> <parameter direction="OUT" name="out_param_varchar" query-parameter="out_param_varchar" type="String"/> </named-stored-procedure-query>
в коде вам просто нужно вызвать вашу процедуру следующим образом:
try { final Query query = this.entityManager .createNamedQuery("PERSIST_PROC_NAME"); query.setParameter("in_param_char", 'V'); resultQuery = (Object[]) query.getSingleResult(); } catch (final Exception ex) { LOGGER.log(ex); throw new TechnicalException(ex); }
чтобы получить два выходных параметра:
Integer myInt = (Integer) resultQuery[0]; String myStr = (String) resultQuery[1];
источник
Это сработало для меня.
@Entity @Table(name="acct") @NamedNativeQueries({ @NamedNativeQuery(callable=true, name="Account.findOne", query="call sp_get_acct(?), resultClass=Account.class)}) public class Account{ // Code }
Примечание: в будущем, если вы решите использовать версию findOne по умолчанию, просто прокомментируйте аннотацию NamedNativeQueries, и JPA переключится на версию по умолчанию.
источник
Этот ответ может быть полезен, если у вас есть менеджер сущностей
У меня была хранимая процедура для создания следующего числа, а на стороне сервера - фреймворк.
Сторона клиента
Object on = entityManager.createNativeQuery("EXEC getNextNmber").executeUpdate(); log.info("New order id: " + on.toString());
Сторона базы данных (SQL-сервер) У меня есть хранимая процедура с именем
getNextNmber
источник
Вы можете использовать
@Query(value = "{call PROC_TEST()}", nativeQuery = true)
в своем репозитории. Это сработало для меня.Внимание: используйте '{' и '}', иначе это не сработает.
источник
JPA 2.0 не поддерживает значения RETURN, только вызовы.
Мое решение было. Создайте ФУНКЦИЮ, вызывающую ПРОЦЕДУРУ.
Итак, внутри кода JAVA вы выполняете НАТИВНЫЙ ЗАПРОС, вызывающий ФУНКЦИЮ оракула.
источник
Для вызова хранимой процедуры мы можем использовать Callable Statement в пакете java.sql.
источник
Попробуйте этот код:
return em.createNativeQuery("{call getEmployeeDetails(?,?)}", EmployeeDetails.class) .setParameter(1, employeeId) .setParameter(2, companyId).getResultList();
источник
persistence.xml
<persistence-unit name="PU2" transaction-type="RESOURCE_LOCAL"> <non-jta-data-source>jndi_ws2</non-jta-data-source> <exclude-unlisted-classes>false</exclude-unlisted-classes> <properties/>
codigo java
String PERSISTENCE_UNIT_NAME = "PU2"; EntityManagerFactory factory2; factory2 = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME); EntityManager em2 = factory2.createEntityManager(); boolean committed = false; try { try { StoredProcedureQuery storedProcedure = em2.createStoredProcedureQuery("PKCREATURNO.INSERTATURNO"); // set parameters storedProcedure.registerStoredProcedureParameter("inuPKEMPRESA", BigDecimal.class, ParameterMode.IN); storedProcedure.registerStoredProcedureParameter("inuPKSERVICIO", BigDecimal.class, ParameterMode.IN); storedProcedure.registerStoredProcedureParameter("inuPKAREA", BigDecimal.class, ParameterMode.IN); storedProcedure.registerStoredProcedureParameter("isbCHSIGLA", String.class, ParameterMode.IN); storedProcedure.registerStoredProcedureParameter("INUSINCALIFICACION", BigInteger.class, ParameterMode.IN); storedProcedure.registerStoredProcedureParameter("INUTIMBRAR", BigInteger.class, ParameterMode.IN); storedProcedure.registerStoredProcedureParameter("INUTRANSFERIDO", BigInteger.class, ParameterMode.IN); storedProcedure.registerStoredProcedureParameter("INTESTADO", BigInteger.class, ParameterMode.IN); storedProcedure.registerStoredProcedureParameter("inuContador", BigInteger.class, ParameterMode.OUT); BigDecimal inuPKEMPRESA = BigDecimal.valueOf(1); BigDecimal inuPKSERVICIO = BigDecimal.valueOf(5); BigDecimal inuPKAREA = BigDecimal.valueOf(23); String isbCHSIGLA = ""; BigInteger INUSINCALIFICACION = BigInteger.ZERO; BigInteger INUTIMBRAR = BigInteger.ZERO; BigInteger INUTRANSFERIDO = BigInteger.ZERO; BigInteger INTESTADO = BigInteger.ZERO; BigInteger inuContador = BigInteger.ZERO; storedProcedure.setParameter("inuPKEMPRESA", inuPKEMPRESA); storedProcedure.setParameter("inuPKSERVICIO", inuPKSERVICIO); storedProcedure.setParameter("inuPKAREA", inuPKAREA); storedProcedure.setParameter("isbCHSIGLA", isbCHSIGLA); storedProcedure.setParameter("INUSINCALIFICACION", INUSINCALIFICACION); storedProcedure.setParameter("INUTIMBRAR", INUTIMBRAR); storedProcedure.setParameter("INUTRANSFERIDO", INUTRANSFERIDO); storedProcedure.setParameter("INTESTADO", INTESTADO); storedProcedure.setParameter("inuContador", inuContador); // execute SP storedProcedure.execute(); // get result try { long _inuContador = (long) storedProcedure.getOutputParameterValue("inuContador"); varCon = _inuContador + ""; } catch (Exception e) { } } finally { } } finally { em2.close(); }
источник
Начиная с JPA 2.1, JPA поддерживает вызов хранимых процедур с использованием динамического StoredProcedureQuery и декларативного @NamedStoredProcedureQuery.
источник
Мое решение было. Создайте ФУНКЦИЮ, вызывающую ПРОЦЕДУРУ.
Итак, внутри кода JAVA вы выполняете НАТИВНЫЙ ЗАПРОС, вызывающий ФУНКЦИЮ оракула.
источник