我正在编写一个简单的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();
我注意到的事情:
{call sp_name(?,?)}
而不是call sp_name(?,?)
getSingleResult
也无法正常工作resultSetMapping
名称或结果类详情答案 0 :(得分:50)
JPA 2.1现在支持存储过程,请阅读Java文档here。
示例:
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");
查看详细示例here。
答案 1 :(得分:21)
我正在Jboss AS中部署我的Web应用程序。我应该使用JPA来访问存储过程或CallableStatement。在这种情况下使用JPA的任何优点。
JPA并不支持它,但它是doable。我仍然不会这样:
因此,我会考虑使用Spring support for JDBC data access或数据映射器(如MyBatis),或者考虑到应用程序的简单性,使用原始JDBC和CallableStatement
。实际上,JDBC可能是我的选择。这是一个基本的启动示例:
CallableStatement cstmt = con.prepareCall("{call getEmployeeDetails(?, ?)}");
cstmt.setInt("employeeId", 123);
cstmt.setInt("companyId", 456);
ResultSet rs = cstmt.executeQuery();
答案 2 :(得分:9)
您需要将参数传递给存储过程。
它应该像这样工作:
List result = em
.createNativeQuery("call getEmployeeDetails(:employeeId,:companyId)")
.setParameter("emplyoyeeId", 123L)
.setParameter("companyId", 456L)
.getResultList();
<强>更新强>
或者也许不应该。
在书籍EJB3 in Action中,它在第383页上显示,JPA does not support stored procedures(页面只是预览,您没有获得全文,整本书可以在几个版本中下载包括this one在内的地方,我不知道这是否合法)。
无论如何,正文是这样的:
如果你是SQL的忠实粉丝,你可能会 愿意利用的力量 数据库存储过程。 不幸的是,JPA不支持 存储过程,你必须 取决于的专有特征 你的持久性提供者。然而, 你可以使用简单的存储功能 (没有输出参数)与原生 SQL查询。
答案 3 :(得分:9)
尽管这个答案详细说明了从存储过程返回记录集, 我在这里发帖,因为我花了很多时间才弄明白,这个帖子帮助了我。
我的应用程序正在使用Eclipselink-2.3.1,但我会强制升级到 Eclipselink-2.5.0,因为JPA 2.1对存储过程有更好的支持。
此方法需要从“org.eclipse.persistence”导入EclipseLink类,因此它特定于Eclipselink实现。
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
此方法独立于实现(不需要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"));
答案 4 :(得分:6)
如果使用EclipseLink,您可以使用@NamedStoredProcedureQuery或StoreProcedureCall来执行任何存储过程,包括具有输出参数或存储游标的存储过程。还支持存储函数和PLSQL数据类型。
请参阅, http://en.wikibooks.org/wiki/Java_Persistence/Advanced_Topics#Stored_Procedures
答案 5 :(得分:6)
对我来说,只有以下内容适用于Oracle 11g和Glassfish 2.1(Toplink):
Query query = entityManager.createNativeQuery("BEGIN PROCEDURE_NAME(); END;");
query.executeUpdate();
带花括号的变体导致ORA-00900。
答案 6 :(得分:4)
对于使用这样的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 FUNCTIONS。
有关如何在使用JPA和Hibernate时调用存储过程和函数的更多详细信息,请查看以下文章
答案 7 :(得分:3)
以下适用于我:
Query query = em.createNativeQuery("BEGIN VALIDACIONES_QPAI.RECALC_COMP_ASSEMBLY('X','X','X',0); END;");
query.executeUpdate();
答案 8 :(得分:2)
对于Sql Srver来说可能不一样,但对于使用oracle和eclipslink的人来说,这对我有用
例如:具有一个IN参数(类型CHAR)和两个OUT参数(NUMBER&amp; VARCHAR)的过程
persistence.xml中的声明了persistence-unit:
<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];
答案 9 :(得分:2)
这对我有用。
@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就会切换到默认值
答案 10 :(得分:1)
如果您有实体经理
,这个答案可能会有所帮助我有一个存储过程来创建下一个数字,而在服务器端我有一个接缝框架。
客户端
Object on = entityManager.createNativeQuery("EXEC getNextNmber").executeUpdate();
log.info("New order id: " + on.toString());
数据库端(SQL服务器)我有一个名为getNextNmber
答案 11 :(得分:1)
JPA 2.0不支持RETURN值,只支持调用。
我的解决方案是。创建一个调用PROCEDURE的函数。
因此,在JAVA代码中,您执行一个调用oracle FUNCTION的NATIVE QUERY。
答案 12 :(得分:0)
试试这段代码:
return em.createNativeQuery("{call getEmployeeDetails(?,?)}",
EmployeeDetails.class)
.setParameter(1, employeeId)
.setParameter(2, companyId).getResultList();
答案 13 :(得分:0)
要调用存储过程,我们可以在java.sql包中使用Callable Statement。
答案 14 :(得分:0)
您可以在存储库中使用@Query(value = "{call PROC_TEST()}", nativeQuery = true)
。这对我有用。
注意:使用“{”和“}”,否则无效。
答案 15 :(得分:0)
的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();
}
答案 16 :(得分:0)
从JPA 2.1开始,JPA支持使用动态StoredProcedureQuery和声明性@NamedStoredProcedureQuery调用存储过程。
答案 17 :(得分:-2)
我的解决方案是。 创建一个调用PROCEDURE的函数。
因此,在JAVA代码中,您执行一个调用oracle FUNCTION的NATIVE QUERY。