jpa - oracle - 数据库链接太多 - ORA-02020

时间:2015-11-20 11:49:05

标签: java oracle jpa

我有@NamedStoredProcedureQuery它看起来像这样:

@NamedStoredProcedureQueries({
    @NamedStoredProcedureQuery(name = "addLongDesc", resultClasses=Integer.class, procedureName = "myProc", parameters = {
        @StoredProcedureParameter(name = "b_cus_id", type = String.class),
        @StoredProcedureParameter(name = "b_case_id", type = String.class),
        @StoredProcedureParameter(name = "b_user_id", type = String.class),
        @StoredProcedureParameter(name = "v_customerno", type = String.class),
        @StoredProcedureParameter(name = "v_tickler_id", type = String.class),
        @StoredProcedureParameter(name = "v_calleruser", type = String.class),
        @StoredProcedureParameter(name = "v_megalltext", type = String.class)
    })
})

我试图以这种方式调用@NamedStoredProcedureQuery

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public boolean changeLongDesc(KallerMainFormParam formObj, String longDesc) {

    Integer result = 0;

    try {
    result = (Integer) em.createNamedQuery("addLongDesc")
                    .setParameter("b_cus_id", formObj.getKallerCusInstance().getId().toString())
                    .setParameter("b_case_id", formObj.getKallerCaseInstance().getId().toString())
                    .setParameter("b_user_id", formObj.getKallerUsr().getId().toString())
                    .setParameter("v_customerno", formObj.getKallerCusInstance().getCustomerno())
                    .setParameter("v_tickler_id", formObj.getKallerCaseInstance().getBKallerCaseData().getTicklerId().toString())
                    .setParameter("v_calleruser", formObj.getKallerUsr().getJazzUser())
                    .setParameter("v_megalltext", "B - " + longDesc).getSingleResult();
    }
    catch (Exception ex) {
        LOG.warning(ex.getMessage());
    }

    return result != 0;

}

oracle数据库中的过程看起来像这样:

CREATE OR REPLACE procedure myProc (b_cus_id number , b_case_id number, b_user_id number, v_customerno varchar2, v_tickler_id number, v_calleruser varchar2, v_megalltext varchar2)
as
result number;
begin
result := remoteDbProc@DBLINK(v_tickler_id , v_megalltext, v_calleruser);
insert into b_Tickler_Access_Log VALUES (B_CASE_TICKLER_SEQ.nextval, v_customerno, b_cus_id, b_case_id,b_user_id,v_tickler_id, 'LONG_DESC', v_jazz_result, sysdate);    
end;

如果请求数量很少,一切正常。但是如果用户开始使用应用程序并且请求的数量越来越多,我得到了ORA-02020的内部数据库异常 - 使用中的数据库链接太多错误。

我尝试将此行添加到存储过程的末尾:EXECUTE IMMEDIATE 'ALTER SESSION CLOSE DATABASE LINK DBLINK';

但这没有帮助。

不幸的是我无法设置INIT.ORA open_links最大参数,我也不能问DBA。

有人可以告诉我如何在没有DBA设置的情况下解决这个问题吗?

非常感谢!

1 个答案:

答案 0 :(得分:0)

你不能说EXECUTE IMMEDIATE 'ALTER SESSION CLOSE DATABASE LINK DBLINK';为什么没有帮助,所以我只能推测。

如果未提交会话,则无法关闭数据库LINK。

这里有一些疑难解答提示

会话的开放链接显示在

select db_link, in_transaction from V$DBLINK;

另请注意,使用DB LINK时,即使使用SELECT(您也不需要更新),也可以打开交易。

DEMO    NO
DEMO2   YES

您可能需要特权

grant select on V_$DBLINK to your_user;

访问此视图(我知道这需要DBA,但请求的风险很简单:)

因此,在上面的示例中,您可以关闭数据库链接DEMO,但不能关闭DEMO2。

尝试这样做,您获得ORA-02080: "database link is in use"并且链接仍然保持打开状态。

<强>更新

如上所述,在事务处于打开状态时,DB LINK会话无法关闭,因此在调用远程过程(实际上是函数)之后关闭DB LINK的最简单方法是显式的提交。

这可能是某种方式如下(我使用你的程序的简化版本)

CREATE OR REPLACE procedure myProc (id number )
as
result number;
begin
result := remoteDbFun@DEMO(1);
-- add this to close transaction and close DB link
commit;
EXECUTE IMMEDIATE 'ALTER SESSION CLOSE DATABASE LINK DEMO';
--
insert into Access_Log VALUES (result, sysdate);    
end;
/

这种方法的一个重大缺点是你结束了交易 - 这可能会与你的交易控制产生冲突。因此,您可以使用autonomous transaction来避免它。

这是通过使用自治事务定义的子函数来完成的,该子函数调用远程函数,进行COMMIT(但是自主,即主会话不可见)并关闭DB LINK。

CREATE OR REPLACE function myFun (id number ) return NUMBER as
PRAGMA AUTONOMOUS_TRANSACTION;

result number;
begin
result := remoteDbFun@DEMO(1);
commit;
EXECUTE IMMEDIATE 'ALTER SESSION CLOSE DATABASE LINK demo';
return result;
end;
/

你的程序myProc调用而不是远程功能这个新功能。 保证在通话结束后没有DB LINK打开。