Java 甲骨文没有';t关闭结果集后删除游标
注意:我们重用单个连接Java 甲骨文没有';t关闭结果集后删除游标,java,oracle,jdbc,cursor,resultset,Java,Oracle,Jdbc,Cursor,Resultset,注意:我们重用单个连接 ************************************************ public Connection connection() { try { if ((connection == null) || (connection.isClosed())) { if (connection!=null) log.severe("Conne
************************************************
public Connection connection() {
try {
if ((connection == null) || (connection.isClosed()))
{
if (connection!=null)
log.severe("Connection was closed !");
connection = DriverManager.getConnection(jdbcURL, username, password);
}
} catch (SQLException e) {
log.severe("can't connect: " + e.getMessage());
}
return connection;
}
**************************************************
public IngisObject[] select(String query, String idColumnName, String[] columns) {
Connection con = connection();
Vector<IngisObject> objects = new Vector<IngisObject>();
try {
Statement stmt = con.createStatement();
String sql = query;
ResultSet rs =stmt.executeQuery(sql);//oracle increases cursors count here
while(rs.next()) {
IngisObject o = new IngisObject("New Result");
o.setIdColumnName(idColumnName);
o.setDatabase(this);
for(String column: columns)
o.attrs().put(column, rs.getObject(column));
objects.add(o);
}
rs.close();// oracle don't decrease cursor count here, while it's expected
stmt.close();
}
catch (SQLException ex) {
System.out.println(query);
ex.printStackTrace();
}
************************************************
公共连接(){
试一试{
if((connection==null)| |(connection.isClosed()))
{
if(连接!=null)
严重(“连接已关闭!”);
connection=DriverManager.getConnection(jdbcURL、用户名、密码);
}
}捕获(SQLE异常){
log.severy(“无法连接:+e.getMessage());
}
回路连接;
}
**************************************************
public IngisObject[]选择(字符串查询、字符串idColumnName、字符串[]列){
连接con=连接();
向量对象=新向量();
试一试{
语句stmt=con.createStatement();
字符串sql=query;
ResultSet rs=stmt.executeQuery(sql);//oracle在此处增加游标计数
while(rs.next()){
IngisObject o=新的IngisObject(“新结果”);
o、 setIdColumnName(idColumnName);
o、 setDatabase(this);
for(字符串列:列)
o、 attrs().put(列,rs.getObject(列));
添加(o);
}
rs.close();//oracle不会在此处减少光标计数,这是预期的
stmt.close();
}
catch(SQLException-ex){
System.out.println(查询);
例如printStackTrace();
}
通常,您会将ResultSet和Statement的close语句放入finally
块中,以确保即使发生异常(可能是您在这里遇到的问题),也会调用它们。在当前代码中,如果发生SQLException,则两个close()方法调用永远不会发生,游标将保持打开状态
另外,您在Oracle中使用什么查询来查看打开的游标数
编辑:该代码应该正在关闭光标。如果没有关闭,则您应该能够看到调用方法与光标计数之间的1:1相关性上升1。确保没有任何意外的过程导致光标计数上升 如果您有权限,您可以对数据库运行此查询,以查看按sid打开的游标计数,以查看是否是其他进程增加了游标,而不是您的进程。如果打开的游标超过10个,它将回调任何游标,您可以通过使用用户名或奥瑟尔:
select oc.sid,
count(*) numCur,
s.username username,
s.osuser osuser,
oc.sql_text,
s.program
from v$open_cursor oc,
v$session s
where s.sid = oc.sid
group by oc.sid,
oc.sql_text,
s.username,
s.osuser,
s.program
having count(*) > 10
order by oc.sid;
如果多个sid使用相同的查询字符串,则另一个查询可能会有所帮助,因此上述查询无法很好地揭示违规者:
select oc.sql_text, count(*)
from v$open_cursor oc
group by oc.sql_text
having count(*) > 10
order by count(*) desc;
正确的方法是在自己的try/catch块中关闭finally块中的每个资源。我通常使用如下静态实用程序类:
public class DatabaseUtils
{
public static void close(Connection connection)
{
try
{
if (connection != null)
{
connection.close();
}
}
catch (SQLException e)
{
// log exception here.
}
}
// similar methods for ResultSet and Statement
}
public IngisObject[] select(String query, String idColumnName, String[] columns) {
Vector<IngisObject> objects = new Vector<IngisObject>();
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
try
{
connection = connection();
stmt = con.createStatement();
// This is a SQL injection attack waiting to happen; I'd recommend PreparedStatemen
String sql = query;
rs =stmt.executeQuery(sql);//oracle increases cursors count here
while(rs.next())
{
IngisObject o = new IngisObject("New Result");
o.setIdColumnName(idColumnName);
o.setDatabase(this);
for(String column: columns) o.attrs().put(column, rs.getObject(column));
objects.add(o);
}
}
catch (SQLException ex)
{
System.out.println(query);
ex.printStackTrace();
}
finally
{
DatabaseUtils.close(rs);
DatabaseUtils.close(stmt);
DatabaseUtils.close(con);
}
所以我会这样写你的代码:
public class DatabaseUtils
{
public static void close(Connection connection)
{
try
{
if (connection != null)
{
connection.close();
}
}
catch (SQLException e)
{
// log exception here.
}
}
// similar methods for ResultSet and Statement
}
public IngisObject[] select(String query, String idColumnName, String[] columns) {
Vector<IngisObject> objects = new Vector<IngisObject>();
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
try
{
connection = connection();
stmt = con.createStatement();
// This is a SQL injection attack waiting to happen; I'd recommend PreparedStatemen
String sql = query;
rs =stmt.executeQuery(sql);//oracle increases cursors count here
while(rs.next())
{
IngisObject o = new IngisObject("New Result");
o.setIdColumnName(idColumnName);
o.setDatabase(this);
for(String column: columns) o.attrs().put(column, rs.getObject(column));
objects.add(o);
}
}
catch (SQLException ex)
{
System.out.println(query);
ex.printStackTrace();
}
finally
{
DatabaseUtils.close(rs);
DatabaseUtils.close(stmt);
DatabaseUtils.close(con);
}
public IngisObject[]选择(字符串查询、字符串idColumnName、字符串[]列){
向量对象=新向量();
连接con=null;
语句stmt=null;
结果集rs=null;
尝试
{
连接=连接();
stmt=con.createStatement();
//这是一个即将发生的SQL注入攻击;我推荐PreparedStatemen
字符串sql=query;
rs=stmt.executeQuery(sql);//oracle在此处增加游标数
while(rs.next())
{
IngisObject o=新的IngisObject(“新结果”);
o、 setIdColumnName(idColumnName);
o、 setDatabase(this);
for(String column:columns)o.attrs().put(column,rs.getObject(column));
添加(o);
}
}
catch(SQLException-ex)
{
System.out.println(查询);
例如printStackTrace();
}
最后
{
数据库关闭(rs);
DatabaseUtils.close(stmt);
数据库utils.close(con);
}
init.ora参数open\u cursors
定义了会话一次可以打开的最大游标数。它的默认值为50。如果应用程序超过此数字,则会引发错误“ora-01000:超过最大打开游标数”
因此,当不再需要JDBC资源时,必须关闭它们,特别是java.sql.ResultSet和java.sql.Statement。如果它们没有关闭,则应用程序存在资源泄漏
在重用Connection对象的情况下,您必须了解这样一个事实:只要连接存在且事务尚未结束,打开的oracle游标将保持打开并在使用中。当应用程序提交时,打开的游标将被释放
因此,作为应用程序设计师,您需要知道最复杂事务所需的开放游标的粗略估计
困难在于oracle的内部参数视图(v$open_cursor,v$sesstat,et.al.)无法显示可重用的已打开游标和仍被阻止(不可重用!)的已打开游标之间的差异通过未关闭的ResultSet或语句。如果关闭finally块中的所有语句和ResultSet对象,则应用程序完全正常
调整init.ora参数的工作方式如下(我们的应用程序最多需要800个游标)
我只是遇到了同样的问题,并发现-如果你不关闭连接(因为你以后可能会重新使用它)-您至少需要执行一个或来释放打开的游标,同时关闭结果集和语句。我知道最好最后关闭它们。但是,执行不是问题。在我的测试中不会发生这种情况。@Vladimir:我在回答中添加了其他信息。如果没有引发异常,您的代码应该可以工作。请看t检查sid级别,并确保影响游标计数的是您自己的进程。此查询帮助我解决了问题(最后,我意外地在java中“泄漏”了preparedstatements,oops)。您指的是“ORA-01000:超过最大打开游标数”吗?如果是,请参阅以获取解释。@Oliver Mich