我创建了一个函数来调用for内的PL / SQL并且它正在创建游标泄漏.PL / SQL工作正常,它返回所需的数据,但我注意到游标的数量增加,直到ora超过-1000个最大打开游标和ORA-00604:在递归SQL级别1错误时发生错误。为了检查使用过的游标数,我使用了以下SQL语句:
select *
from
(select a.value, s.username, s.sid, s.serial#
from v$sesstat a, v$statname b, v$session s
where a.statistic# = b.statistic#
and s.sid=a.sid
and b.name = 'opened cursors current')
where sid = 'mySID';
我调试了我的代码,我发现游标是在这里创建的: objectXStructResult.getAttributes()[X] 。我试图关闭结果集和callableStatement但它不起作用。任何人都可以帮助我吗?
function callToDao(){
for(Object X:LstObject){
plsqlCall(X);
}
}
funcion ObjectX plsqlCall(Object X){
Object salidaX = null;
//Obtención de parámetros de consulta
final String p_x1 = X.getX();
final String p_x2 = X.getX();
final String p_x3 = X.getX();
final String p_x4 = X.getX();
final String p_x5 = X.getX();
final String p_x6 = X.getX();
final String p_x7 = X.getX();
try{
CallableStatementCreator csCreator = new CallableStatementCreator() {
@Override
public CallableStatement createCallableStatement(Connection con) throws SQLException {
CallableStatement cs = null;
try {
cs = con.prepareCall("{call PK_XXXXX.XXXXXX(?, ?, ?, ?, ?, ?, ?, ?) }");
cs.setInt(1, Integer.parseInt(p_x1));
cs.setString(2, p_x2);
cs.setString(3, p_x3);
cs.setLong(4, Long.parseLong(p_x4));
cs.setDouble(5,Double.parseDouble(p_x5));
cs.setDouble(6, Double.parseDouble(p_x6));
cs.setDouble(7, Double.parseDouble(p_x7));
cs.registerOutParameter(8, OracleTypes.STRUCT,"OBJECT_PLSQL");
} catch (SQLException e) {
e.printStackTrace();
}
return cs;
}
};
CallableStatementCallback csCallback = new CallableStatementCallback() {
public Object doInCallableStatement(CallableStatement cs) throws SQLException {
ObjectX ret = null;
ResultSet rs = null;
try {
cs.execute();
ret = obtainObjectX(cs, rs, objectPos, type);
} catch (SQLException e) {
e.printStackTrace();
}
return ret;
}
};
salida = (ObjectX) this.jdbcTemplate.execute(csCreator,csCallback);
}catch (Exception e) {
e.printStackTrace();
}
return salida;
}
private ObjectX obtainObjectX(CallableStatement cs, ResultSet rs, int objectPos, String p_tipo) throws SQLException{
ObjectX objectX= new ObjectX();
List<ObjectX> objectXLst= new ArrayList<ObjectX>();
try{
//Obtain exit parameter
STRUCT objectXStructResult = (STRUCT)cs.getObject(objectPos);
//Obtain Struct data
String att1 = (String)objectXStructResult.getAttributes()[1];
String att2 = (String)objectXStructResult.getAttributes()[5];
BigDecimal att3 = (BigDecimal)objectXStructResult.getAttributes()[6];
String att4 = (String)objectXStructResult.getAttributes()[7];
//Control de error en la obtención de datos
if (new BigDecimal("0").equals(att3)){
//Obtención de los datos de salida
ARRAY listaDatos = (ARRAY)objectXStructResult.getAttributes()[0];
if (listaDatos!=null){
rs = listaDatos.getResultSet();
int rowNum = 0;
//Recorrido del listado de datos
while (rs.next()) {
STRUCT dataStruct= (STRUCT) listaDatos.getOracleArray()[rowNum];
ObjectX objXFor= this.mapRow(dataStruct, rowNum);
objectXLst.add(objXFor);
rowNum++;
}
}
objectX.setAtt1(att1);
objectX.setAtt2(att2);
objectX.setAtt3(new Long(att3.toString()));
objectX.setAtt4(att4);
objectX.setData(objectXLst);
}
} catch (Exception e) {
e.printStackTrace();
}
return objectX;
}
private ObjectX mapRow(STRUCT dataStruct, int rowNum) throws SQLException {
Object[] objectInfo = dataStruct.getAttributes();
//Obtención de datos de la estructura de base de datos
BigDecimal att1= ((BigDecimal)objectInfo[0]);
BigDecimal att2= (BigDecimal)objectInfo[1];
String att3= (String)objectInfo[2];
String att4= (String)objectInfo[3];
return new ObjectX(att1, att2, null, att3, null, null, att4, null);
}
更新1:
我已经设法将游标的创建从5改为1改变代码,但我仍然无法找到关闭游标的方法。
自:
String att1 = (String)objectXStructResult.getAttributes()[1];
String att2 = (String)objectXStructResult.getAttributes()[5];
BigDecimal att3 = (BigDecimal)objectXStructResult.getAttributes()[6];
String att4 = (String)objectXStructResult.getAttributes()[7];
//Control de error en la obtención de datos
if (new BigDecimal("0").equals(att3)){
//Obtención de los datos de salida
ARRAY listaDatos = (ARRAY)objectXStructResult.getAttributes()[0];
}
要:
Object[] atributos = objectXStructResult.getAttributes();
String att1 = (String)atributos[1];
String att2 = (String)atributos[5];
BigDecimal att3 = (BigDecimal)atributos[6];
String att4 = (String)atributos[7];
//Control de error en la obtención de datos
if (new BigDecimal("0").equals(att3)){
//Obtención de los datos de salida
ARRAY listaDatos = atributos[0];
}
答案 0 :(得分:0)
注意:应该在回调实现中的finally块中关闭打开的任何ResultSet。 Spring将在返回回调后关闭Statement对象,但这并不一定意味着ResultSet资源将被关闭:Statement对象可能被连接池汇集,close调用只将对象返回到池而不是物理关闭资源。
请注意 jdbcTemplate 会自动关闭 csCreator 和 csCallback ,但您必须始终关注 ResultSet 。请记住在 finally 块中关闭它们,以确保在发生异常时,将调用 close()。
例如,您当前的陈述:
ResultSet rs = null;
try {
cs.execute();
ret = obtainObjectX(cs, rs, objectPos, type);
} catch (SQLException e) {
e.printStackTrace();
}
应替换为:
ResultSet rs = null;
try {
cs.execute();
ret = obtainObjectX(cs, rs, objectPos, type);
} catch (SQLException e) {
e.printStackTrace();
} finally{
if(rs != null)
rs.close()
}
<强>更新强> 来自oracle文档:
默认情况下,不启用自动索引。对于JDBC应用程序,如果可以通过getArray和getResultSet方法随机访问数组元素,则为ARRAY对象启用自动索引。
所以这可能会减少数据库上的开放游标:
array.setAutoIndexing(true);
顺便说一下,不推荐使用 oracle.sql.ARRAY 类:
已过时。使用java.sql.Array接口进行声明,而不是使用具体的类oracle.sql.ARRAY。