从Java / JPA调用存储过程

我正在写一个简单的Web应用程序来调用存储过程并检索一些数据。 它是一个非常简单的应用程序,它与客户端的数据库交互。 我们传递员工ID和公司ID,存储过程将返回员工详细信息。

Web应用程序无法更新/删除数据并正在使用SQL Server。

我正在使用Jboss AS部署我的Web应用程序。 我应该使用JPA来访问存储过程或CallableStatement 。 在这种情况下使用JPA的任何好处。

还有什么将是SQL语句来调用这个存储过程。 我以前从来没有使用过存储过程,而我正在为这个而苦苦挣扎。 谷歌没有太多的帮助。

这里是存储过程:

 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(); 

我已经注意到的事情:

  1. 参数名称不适合我,所以请尝试使用参数索引。
  2. 更正sql语句{call sp_name(?,?)}而不是call sp_name(?,?)
  3. 如果存储过程正在返回一个结果集,即使只知道一行, getSingleResult不会起作用
  4. 传递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"); 

请看这里的详细例子。

我正在使用Jboss AS部署我的Web应用程序。 我应该使用JPA来访问存储过程或CallableStatement。 在这种情况下使用JPA的任何好处。

它不是真的被JPA支持,但它是可行的 。 我仍然不会这样做:

  • 使用JPA只是为了在一些bean中映射一个存储过程调用的结果实在是太过分了,
  • 特别是鉴于JPA是不是真的适合调用存储过程(语法将相当冗长)。

因此,我宁愿考虑使用Spring支持JDBC数据访问 ,或像MyBatis这样的数据映射器,或者考虑到应用程序的简单性,使用原始JDBC和CallableStatement 。 实际上,JDBC可能是我的select。 这是一个基本的开球的例子:

 CallableStatement cstmt = con.prepareCall("{call getEmployeeDetails(?, ?)}"); cstmt.setInt("employeeId", 123); cstmt.setInt("companyId", 456); ResultSet rs = cstmt.executeQuery(); 

参考

  • JDBC文档: Java SE 6

如何使用JPA检索存储过程输出参数(2.0需要EclipseLink导入,2.1不需要)

即使这个答案没有详细说明从存储过程返回logging集,我在这里张贴,因为它花了我很长时间才弄明白,这个线程帮助我。

我的应用程序使用Eclipselink-2.3.1,但是我将强制升级到Eclipselink-2.5.0,因为JPA 2.1对存储过程有更好的支持。

使用EclipseLink-2.3.1 / JPA-2.0:实现相关

这个方法需要从“org.eclipse.persistence”中导入EclipseLink类,所以它特定于Eclipselink实现。

我在“ http://www.yenlo.nl/en/calling-oracle-stored-procedures-from-eclipselink-with-multiple-out-parameters ”find它。

 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:独立于实现(已在此线程中logging)

这个方法是独立实现的(不需要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")); 

您需要将parameter passing给存储过程。

它应该像这样工作:

  List result = em .createNativeQuery("call getEmployeeDetails(:employeeId,:companyId)") .setParameter("emplyoyeeId", 123L) .setParameter("companyId", 456L) .getResultList(); 

更新:

或者,也许它不应该。

在书籍EJB3 in Action中 ,它说在383页上, JPA不支持存储过程 (页面只是预览,不能获得全文,整个图书可以在几个地方下载,包括这个 ,我不知道这是否合法)。

无论如何,文字是这样的:

JPA和数据库存储过程

如果你是SQL的忠实粉丝,你可能愿意利用数据库存储过程的力量。 不幸的是,JPA不支持存储过程,你必须依赖持久化提供者的专有特性。 但是,您可以使用简单的存储函数(不带出参数)与本机SQL查询。

如果使用EclipseLink,则可以使用@NamedStoredProcedureQuery或StoreProcedureCall来执行任何存储过程,包括具有输出参数的存储过程或超出的游标。 还支持存储函数和PLSQL数据types。

请参阅http://en.wikibooks.org/wiki/Java_Persistence/Advanced_Topics#Stored_Procedures

对我而言,只有以下几方面与Oracle 11g和Glassfish 2.1(Toplink)合作:

 Query query = entityManager.createNativeQuery("BEGIN PROCEDURE_NAME(); END;"); query.executeUpdate(); 

带有花括号的变体导致了ORA-00900。

以下为我工作:

 Query query = em.createNativeQuery("BEGIN VALIDACIONES_QPAI.RECALC_COMP_ASSEMBLY('X','X','X',0); END;"); query.executeUpdate(); 

对Sql Srver来说可能不一样,但对于使用oracle和eclipslink的人来说,这对我来说是工作的

例如:一个IN参数(CHARtypes)和两个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中声明proc的结构

 <?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> 

在代码中你只需要像这样调用你的proc:

 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]; 

如果你有实体经理,这个答案可能会有帮助

我有一个存储过程来创build下一个数字,并在服务器端我有缝框架。

客户端

  Object on = entityManager.createNativeQuery("EXEC getNextNmber").executeUpdate(); log.info("New order id: " + on.toString()); 

数据库端(SQL服务器)我有存储过程名为getNextNmber

要调用存储过程,我们可以在java.sql包中使用Callable Statement。

试试这个代码:

 return em.createNativeQuery("{call getEmployeeDetails(?,?)}", EmployeeDetails.class) .setParameter(1, employeeId) .setParameter(2, companyId).getResultList(); 

您可以在存储库中使用@Query(value = "{call PROC_TEST()}", nativeQuery = true) 。 这对我有效。

注意:使用“{”和“}”,否则它将不起作用。

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/> 

鳕鱼爪哇

  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.0不支持RETURN值,只能调用。

我的解决scheme是。 创build一个函数调用PROCEDURE。

所以,在JAVA代码里面执行一个调用oracle FUNCTION的NATIVE QUERY。

我的解决scheme是。 创build一个函数调用PROCEDURE。

所以,在JAVA代码里面执行一个调用oracle FUNCTION的NATIVE QUERY。