用JPA执行数据库功能
Execute database function with JPA
要调用 Oracle 数据库函数,我只需编写
final Query query = entityManager.createNativeQuery(
"select myfunction(?) from dual"
);
query.setParameter(1, "value");
Object rv = query.getSingleResult();
只要被调用的函数不执行任何 dml 操作,它就可以工作。
否则我将不得不执行类似
{? = call myfunction(?)}
不幸的是,我无法注册任何 OUT 参数,因此无法使该语句生效。
我如何在不使用普通 JDBC 的情况下实现这一目标?
编辑:
这个问题具有误导性。我想获取 Oracle 数据库中函数(不是存储过程)的结果。没有 OUT 参数。该函数可能如下所示:
CREATE OR REPLACE FUNCTION myfunction(value IN VARCHAR2)
RETURN VARCHAR2
IS
BEGIN
UPDATE foo SET bar = 'foobar'
WHERE id = 1;
RETURN 'test';
END myfunction;
Calling an oracle function from JPA 的答案没有解决我的问题,因为我的函数中有 dml 更改。我得到一个错误:
cannot perform a DML operation inside a query
您必须使用 StoredProcedureQuery:
StoredProcedureQuery query = this.em.createStoredProcedureQuery("myfunction");
query.registerStoredProcedureParameter("inparam", String.class, ParameterMode.IN);
query.registerStoredProcedureParameter("outparam", String.class, ParameterMode.OUT);
// set input parameter
query.setParameter("inparam", "Hello);
// call the stored procedure and get the result
query.execute();
String result = (String) query.getOutputParameterValue("sum");
如果您期望一个或多个结果,您可以使用
getSingleResult() or getResultList()
喜欢查询接口而不是 getOutputParameterValue()
在此处查找更多信息:
https://www.thoughts-on-java.org/call-stored-procedures-jpa-part-2/
- Select 当函数中有任何 DML 语句时,查询将不起作用。
如果没有 DML 语句,那么 SELECT QUERY 是最好和最有效的方法。
- 如果有DML语句,就得用接口CallableStatement。
当我们在我们的项目中使用 JDBC 时,这是非常向前的,但是对于 Spring 项目,即使用 JPA,我们将需要从 EntityManager 和 ReturningWork 获取会话。
Session session = entityManager.unwrap(Session.class);
CallableStatement callableStatement = session.doReturningWork(new ReturningWork<CallableStatement>() {
@Override
public CallableStatement execute(Connection connection) throws SQLException {
CallableStatement function = connection.prepareCall(
"{ ? = call package_name.function_name(?,?) }");
function.registerOutParameter(1, Types.INTEGER);
function.setLong(2, 56);
function.setString(3,"some text");
function.execute();
return function;
}
});
try {
return callableStatement.getBigDecimal(1);
} catch (SQLException e) {
e.printStackTrace();
return null;
}
要调用 Oracle 数据库函数,我只需编写
final Query query = entityManager.createNativeQuery(
"select myfunction(?) from dual"
);
query.setParameter(1, "value");
Object rv = query.getSingleResult();
只要被调用的函数不执行任何 dml 操作,它就可以工作。 否则我将不得不执行类似
{? = call myfunction(?)}
不幸的是,我无法注册任何 OUT 参数,因此无法使该语句生效。 我如何在不使用普通 JDBC 的情况下实现这一目标?
编辑:
这个问题具有误导性。我想获取 Oracle 数据库中函数(不是存储过程)的结果。没有 OUT 参数。该函数可能如下所示:
CREATE OR REPLACE FUNCTION myfunction(value IN VARCHAR2)
RETURN VARCHAR2
IS
BEGIN
UPDATE foo SET bar = 'foobar'
WHERE id = 1;
RETURN 'test';
END myfunction;
Calling an oracle function from JPA 的答案没有解决我的问题,因为我的函数中有 dml 更改。我得到一个错误:
cannot perform a DML operation inside a query
您必须使用 StoredProcedureQuery:
StoredProcedureQuery query = this.em.createStoredProcedureQuery("myfunction");
query.registerStoredProcedureParameter("inparam", String.class, ParameterMode.IN);
query.registerStoredProcedureParameter("outparam", String.class, ParameterMode.OUT);
// set input parameter
query.setParameter("inparam", "Hello);
// call the stored procedure and get the result
query.execute();
String result = (String) query.getOutputParameterValue("sum");
如果您期望一个或多个结果,您可以使用
getSingleResult() or getResultList()
喜欢查询接口而不是 getOutputParameterValue()
在此处查找更多信息: https://www.thoughts-on-java.org/call-stored-procedures-jpa-part-2/
- Select 当函数中有任何 DML 语句时,查询将不起作用。
如果没有 DML 语句,那么 SELECT QUERY 是最好和最有效的方法。 - 如果有DML语句,就得用接口CallableStatement。
当我们在我们的项目中使用 JDBC 时,这是非常向前的,但是对于 Spring 项目,即使用 JPA,我们将需要从 EntityManager 和 ReturningWork 获取会话。
Session session = entityManager.unwrap(Session.class);
CallableStatement callableStatement = session.doReturningWork(new ReturningWork<CallableStatement>() {
@Override
public CallableStatement execute(Connection connection) throws SQLException {
CallableStatement function = connection.prepareCall(
"{ ? = call package_name.function_name(?,?) }");
function.registerOutParameter(1, Types.INTEGER);
function.setLong(2, 56);
function.setString(3,"some text");
function.execute();
return function;
}
});
try {
return callableStatement.getBigDecimal(1);
} catch (SQLException e) {
e.printStackTrace();
return null;
}