我有@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设置的情况下解决这个问题吗?
非常感谢!
答案 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打开。