如何使用Eclipselink运行Oracle PROCEDURE 2.4返回SYS_REFCURSOR

时间:2017-05-05 19:06:51

标签: java oracle jpa stored-procedures eclipselink

我非常希望得到你的帮助,我尝试了几件事,但我无法解决问题。

我正在使用: Eclipselink 2.42 Oracle 11

我需要执行一个返回 SYS_REFCURSOR 的过程,但我无法使用eclipselink(JPA)执行此过程,我尝试了几种方式,似乎对我来说,API没有识别SYS_REFCURSOR类型。

有人可以帮助我,我已经没有想法,做这项工作

这是我的程序:

PROCEDURE RETRIEVE_JOBS(JOB_ID_PARAM IN  FAC_JOB_INTEGRATION.FACT_JOB_ENTRY_REC
                        , JOBS_PARAM OUT SYS_REFCURSOR) IS

  vDescErro VARCHAR2(2000);

  BEGIN 
    OPEN JOBS_PARAM FOR
      SELECT * 
      FROM   dba_jobs
      --WHERE  job = NVL(pJOB,job)
      ORDER BY job;

  EXCEPTION WHEN OTHERS THEN
    vDescErro := REPLACE(SQLERRM, '"' ,' ');
    vDescerro := REPLACE(vDescErro, CHR(10),'');

END RETRIEVE_JOBS;

以下是一些测试结果:

StoredProcedureCall functionCall = new StoredProcedureCall();
functionCall.setProcedureName("FAC_JOB_INTEGRATION.RETRIEVE_JOBS");
functionCall.addNamedArgument("JOB_ID_PARAM");
functionCall.useNamedCursorOutputAsResultSet("JOBS_PARAM");
DataReadQuery querytestS = new DataReadQuery();
querytestS.addArgument("JOB_ID_PARAM");
querytestS.setCall(functionCall);
// Adding arguments
List<Object> queryArgstestS = new ArrayList<Object>();
queryArgstestS.add(entrada);
querytestS.bindAllParameters();
// Executing query
session = ((JpaEntityManager)getEntityManager().getDelegate()).getActiveSession();
Object result232 = session.executeQuery(querytestS, queryArgstestS);

我的错误:

[EL Fine]: 2017-05-05 15:33:03.886--ServerSession(23378162)--Connection(19739591)--BEGIN FAC_JOB_INTEGRATION.RETRIEVE_JOBS(JOB_ID_PARAM=>?, JOBS_PARAM=>?); END;
    bind => [TipoEntrada [jobId=200], => JOBS_PARAM]
[EL Fine]: 2017-05-05 15:33:03.886--ServerSession(23378162)--SELECT 1 FROM DUAL
[EL Warning]: 2017-05-05 15:33:04.06--UnitOfWork(19720277)--Local Exception Stack: 
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.4.2.v20130514-5956486): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: Invalid type Column
Error Code: 17004
Call: BEGIN FAC_JOB_INTEGRATION.RETRIEVE_JOBS(JOB_ID_PARAM=>?, JOBS_PARAM=>?); END;
    bind => [TipoEntrada [jobId=200], => JOBS_PARAM]
Query: DataReadQuery()

第二次测试:

PLSQLStoredProcedureCall call2 = new PLSQLStoredProcedureCall();
call2.setProcedureName("FAC_JOB_INTEGRATION.RETRIEVE_JOBS");
call2.addNamedArgument("JOB_ID_PARAM", TipoEntrada.getRecord());
call2.useNamedCursorOutputAsResultSet("JOBS_PARAM");
DataReadQuery   querytest = new DataReadQuery ();  
querytest.addArgument("JOB_ID_PARAM");  
querytest.setCall(call2);  
// Adding arguments  
List<Object> queryArgstest = new ArrayList<Object>();  
queryArgstest.add(entrada);  
querytest.bindAllParameters();  
// Executing query  
session = ((JpaEntityManager) 
getEntityManager().getDelegate()).getActiveSession();
Object result23 = session.executeQuery(querytest, queryArgstest);

错误结果:

Local Exception Stack: 
Exception [EclipseLink-6148] (Eclipse Persistence Services - 2.4.2.v20130514-5956486): org.eclipse.persistence.exceptions.QueryException
Exception Description: Adding named OUT cursor arguments without DatabaseType classification to PLSQLStoredProcedureCall is not supported.
    at org.eclipse.persistence.exceptions.QueryException.addArgumentsNotSupported(QueryException.java:1417)

现在我创建一个OracleCursorDatabaseType:

import static org.eclipse.persistence.internal.helper.DatabaseType.DatabaseTypeHelper.databaseTypeHelper;
import static org.eclipse.persistence.internal.helper.Helper.NL;

import java.util.List;
import java.util.ListIterator;

import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.internal.helper.SimpleDatabaseType;
import org.eclipse.persistence.internal.sessions.AbstractRecord;
import org.eclipse.persistence.platform.database.DatabasePlatform;
import org.eclipse.persistence.platform.database.oracle.plsql.PLSQLStoredProcedureCall;
import org.eclipse.persistence.platform.database.oracle.plsql.PLSQLargument;
import org.eclipse.persistence.queries.StoredProcedureCall;
import org.eclipse.persistence.sessions.DatabaseRecord;

import oracle.jdbc.OracleTypes;

@SuppressWarnings("rawtypes")
public class OracleCursorDatabaseType implements SimpleDatabaseType {

    public boolean isComplexDatabaseType() {
        return false;
    }

    public boolean isJDBCType() {
        return false;
    }

    public int getSqlCode() {
        return OracleTypes.CURSOR;
    }

    public int getConversionCode() {
        return getSqlCode();
    }

    public String getTypeName() {
        return "SYS_REFCURSOR";
    }

    public int computeInIndex(PLSQLargument inArg, int newIndex, ListIterator<PLSQLargument> i) {
        inArg.outIndex = newIndex;
        return ++newIndex;
    }

    public int computeOutIndex(PLSQLargument outArg, int newIndex, ListIterator<PLSQLargument> iterator) {
        outArg.outIndex = newIndex;
        return newIndex;
    }

    public void buildInDeclare(StringBuilder sb, PLSQLargument inArg) {
        System.out.println("buildInDeclare");
    }

    public void buildOutDeclare(StringBuilder sb, PLSQLargument outArg) {
        sb.append(" ");
        sb.append(databaseTypeHelper.buildTarget(outArg));
        sb.append(" ");
        sb.append(getTypeName());
        sb.append(";");
        sb.append(NL);
    }

    public void buildBeginBlock(StringBuilder sb, PLSQLargument arg, PLSQLStoredProcedureCall call) {
        System.out.println("buildBeginBlock");

    }

    public void buildOutAssignment(StringBuilder sb, PLSQLargument outArg, PLSQLStoredProcedureCall call) {
        String target = databaseTypeHelper.buildTarget(outArg);
        sb.append(" :");
        sb.append(outArg.outIndex);
        sb.append(" := ");
        sb.append(target);
        sb.append(";");
        sb.append(NL);
    }

    public void translate(PLSQLargument arg, AbstractRecord translationRow, AbstractRecord copyOfTranslationRow, List<DatabaseField> copyOfTranslationFields, List<DatabaseField> translationRowFields,
            List translationRowValues, StoredProcedureCall call) {
        // TODO Auto-generated method stub
        System.out.println("translate");
    }

    public void buildOutputRow(PLSQLargument outArg, AbstractRecord outputRow, DatabaseRecord newOutputRow, List<DatabaseField> outputRowFields, List outputRowValues) {
        databaseTypeHelper.buildOutputRow(outArg, outputRow, newOutputRow, outputRowFields, outputRowValues);
    }

    public void logParameter(StringBuilder sb, Integer direction, PLSQLargument arg, AbstractRecord translationRow, DatabasePlatform platform) {
        System.out.println("logParameter");
    }
}

第一次测试:

PLSQLStoredProcedureCall call2 = new PLSQLStoredProcedureCall();
call2.setProcedureName("FAC_JOB_INTEGRATION.RETRIEVE_JOBS");
call2.addNamedArgument("JOB_ID_PARAM", TipoEntrada.getRecord());
call2.addNamedOutputArgument("JOBS_PARAM", new OracleCursorDatabaseType());
// Preparing the query  
DataReadQuery   querytest = new DataReadQuery ();  
querytest.addArgument("JOB_ID_PARAM");  
querytest.setCall(call2);  
// Adding arguments  
List<Object> queryArgstest = new ArrayList<Object>();  
queryArgstest.add(entrada);  
querytest.bindAllParameters();  
// Executing query  
session = ((JpaEntityManager) getEntityManager().getDelegate()).getActiveSession();
Object result23 = session.executeQuery(querytest, queryArgstest);

PROCEDURE运行没有问题,但不返回游标值:

日志执行:

[EL Fine]: 2017-05-05 15:51:55.933--ServerSession(23378162)--Connection(15936168)--
DECLARE
  JOB_ID_PARAMTARGET FAC_JOB_INTEGRATION.FACT_JOB_ENTRY_REC;
  JOB_ID_PARAMCOMPAT FACT_JOB_ENTRY := :1;
 JOBS_PARAMTARGET SYS_REFCURSOR;
  FUNCTION EL_SQL2PL_1(aSqlItem FACT_JOB_ENTRY) 
  RETURN FAC_JOB_INTEGRATION.FACT_JOB_ENTRY_REC IS
    aPlsqlItem FAC_JOB_INTEGRATION.FACT_JOB_ENTRY_REC;
  BEGIN
    aPlsqlItem.JOB := aSqlItem.JOB;
    RETURN aPlsqlItem;
  END EL_SQL2PL_1;
BEGIN
  JOB_ID_PARAMTARGET := EL_SQL2PL_1(JOB_ID_PARAMCOMPAT);
  FAC_JOB_INTEGRATION.RETRIEVE_JOBS(JOB_ID_PARAM=>JOB_ID_PARAMTARGET, JOBS_PARAM=>JOBS_PARAMTARGET);
 :2 := JOBS_PARAMTARGET;
END;
  bind => [:1 => TipoEntrada [jobId=200], ]

对象值:

[DatabaseRecord(JOBS_PARAM => [])]

更新1

我尝试了另一种方式,现在使用eclipselink的ScrollableCursor,我可以执行该过程并返回一个Cursor,但是当我尝试通过它时,我的结果集很接近。

我尝试了几种方法让它打开,包括拥有持久性单元(RESOURCE_LOCAL),但我没有成功。

任何人都有任何提示吗?

异常[EclipseLink-4002](Eclipse Persistence Services - 2.4.2.v20130514-5956486):org.eclipse.persistence.exceptions.DatabaseException 内部异常:java.sql.SQLException:结果集已关闭

EntityManagerFactory createEntityManagerFactory = Persistence.createEntityManagerFactory("localFactPU");

        //EntityManager em = FJPAManager.getInstance().getEntityManagerContext("localFactPU").getEntityManager();

        EntityManager em = createEntityManagerFactory.createEntityManager();
        em.getTransaction().begin();

        em.getTransaction().isActive();
        System.out.println(em.isOpen());


        //em.getTransaction().begin();

        ReadAllQuery databaseQuery = new ReadAllQuery(DBAJobsOracleEntity.class);
        databaseQuery.useCursoredStream();
        StoredProcedureCall calles = new StoredProcedureCall();
        calles.setProcedureName("FAC_JOB_INTEGRATION.TEST_ESTEVAO");
        calles.useNamedCursorOutputAsResultSet("JOBS_PARAM");
        databaseQuery.setCall(calles);

        databaseQuery.useCursoredStream();
        databaseQuery.useScrollableCursor(1000);
        //session = ((JpaEntityManager) getEntityManager().getDelegate()).getActiveSession();
        //session.executeQuery(databaseQuery);


        //JpaQuery  queryess = (JpaQuery) ((JpaEntityManager)getEntityManager().getDelegate()).createQuery(databaseQuery);
        JpaQuery  queryess = (JpaQuery) ((JpaEntityManager)em.getDelegate()).createQuery(databaseQuery);
        queryess.setHint(QueryHints.CURSOR, true);
        queryess.setHint(QueryHints.CURSOR_INITIAL_SIZE, 2);
        queryess.setHint(QueryHints.CURSOR_PAGE_SIZE, 5);
        queryess.setHint(QueryHints.RESULT_SET_CONCURRENCY, ResultSetConcurrency.ReadOnly);

        String resultSetType = ResultSetType.DEFAULT;
        queryess.setHint(QueryHints.RESULT_SET_TYPE, resultSetType);
        ScrollableCursor scrollableCursor = (ScrollableCursor)queryess.getResultCursor();

        DatabaseSessionImpl databaseSession = ((JpaEntityManager)em.getDelegate()).getDatabaseSession();
        scrollableCursor.setSession(databaseSession);

        scrollableCursor.next();
        scrollableCursor.close();

1 个答案:

答案 0 :(得分:0)

你可以尝试

StoredProcedureQuery query = em.createNamedStoredProcedureQuery("RETRIEVE_JOBS");
query.setParameter("JOB_ID_PARAM", 9999);
query.execute();
List<YourClass.class> result = (List<YourClass.class>)query.getOutputParameterValue("JOBS_PARAM");

或者在您的实体类中尝试

   @NamedStoredProcedureQuery(name = "findJobs", 
                           procedureName = "RETRIEVE_JOBS", 
                           resultClass = <YourEntityClassName>.class, 
                           parameters = { 
            @StoredProcedureParameter(queryParameter = "JobId", name = "JOB_ID_PARAM", 
                                      direction = Direction.IN, 
                                      type = String.class)
            , 
            @StoredProcedureParameter(queryParameter = 
                                     "my_cursor", 
                                     name = 
                                     "JOBS_PARAM", 
                                     direction = 
                                     Direction.OUT_CURSOR)})