Vla*_*mir 18 java oracle jdbc resultset cursor
注意:我们重用单一连接.
************************************************
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();
}
Run Code Online (Sandbox Code Playgroud)
Oli*_*els 24
init.ora参数open_cursors定义会话一次可以拥有的打开游标的最大值.它的默认值为50.如果应用程序超过此数,则会引发错误"ORA-01000:超出最大打开游标数".
因此,当不再需要JDBC资源时,必须关闭它们,特别是java.sql.ResultSet和java.sql.Statement.如果它们未关闭,则应用程序存在资源泄漏.
在重用Connection对象的情况下,您必须意识到只要连接存在且事务尚未结束,打开的oracle游标就会保持打开和使用.当应用程序提交时,释放的游标将被释放.
因此,作为应用程序设计人员,您需要了解对最复杂事务所需的开放游标的粗略估计.
困难在于oracle的内部参数视图(v $ open_cursor,v $ sesstat等等)无法显示打开的游标(可重复使用和打开的游标)之间的区别,这些游标仍然被阻止(不可重复使用!)未公开的ResulSet或Statement.如果关闭finally块中的所有Statement和ResultSet对象,则应用程序完全正常.
调整init.ora参数的工作原理如下(我们的应用程序最多需要800个游标)
ALTER SYSTEM SET open_cursors = 800 SCOPE=BOTH;
Run Code Online (Sandbox Code Playgroud)
通常,您会将ResultSet和Statement的close语句放入finally块中,以确保即使发生异常也可以调用它们(可能是您在此处遇到的问题).在当前代码中,如果发生SQLException,则两个close()方法调用将永远不会发生,并且游标将保持打开状态.
您还在Oracle中使用什么查询来查看打开游标的数量?
编辑:
该代码应该关闭光标.如果不是那么你应该能够看到调用方法和光标计数增加1的1对1相关性.确保没有一些意外的进程导致光标计数上升.
如果您具有这些权限,则可以对数据库运行此查询以查看sid打开的游标数,以查看是否可能是某些其他进程正在增加游标而不是特定于游标.如果打开超过10个光标,它会向后拉,你可以通过用户名或osuser来提升它以滤除噪音或缩小它:
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;
Run Code Online (Sandbox Code Playgroud)
另一个可能有用的查询,如果多个sid使用相同的查询字符串,那么上面的内容并没有很好地揭示犯罪者:
select oc.sql_text, count(*)
from v$open_cursor oc
group by oc.sql_text
having count(*) > 10
order by count(*) desc;
Run Code Online (Sandbox Code Playgroud)
正确的方法是在自己的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
}
Run Code Online (Sandbox Code Playgroud)
所以我写这样的代码:
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);
}
Run Code Online (Sandbox Code Playgroud)
我只是遇到了同样的问题并发现 - 如果你没有关闭连接(因为你可能会在以后重复使用它) - 你至少需要做一个connection.rollback()或connection.commit()来释放open游标与关闭ResultSet和语句一起使用.
| 归档时间: |
|
| 查看次数: |
62195 次 |
| 最近记录: |