我收到 ORA-01000 SQL 异常。所以我有一些相关的疑问。
{ //method try starts
String sql = "INSERT into TblName (col1, col2) VALUES(?, ?)";
pStmt = obj.getConnection().prepareStatement(sql);
pStmt.setLong(1, subscriberID);
for (String language : additionalLangs) {
pStmt.setInt(2, Integer.parseInt(language));
pStmt.execute();
}
} //method/try ends
{ //finally starts
pStmt.close()
} //finally ends
编辑1:
6. 使用弱/软引用语句对象是否有助于防止泄漏?
编辑2:
1. 有什么办法可以在我的项目中找到所有丢失的“statement.close()”?我知道这不是内存泄漏。但是我需要找到一个符合垃圾收集条件的语句引用(不执行 close() 的地方)?有什么可用的工具吗?还是我必须手动分析它?
请帮助我理解它。
解决方案
在 Oracle DB 中为用户名 -VELU 查找打开的游标
转到 ORACLE 机器并以 sysdba 身份启动 sqlplus。
[oracle@db01 ~]$ sqlplus / as sysdba
然后运行
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'
AND USERNAME = 'VELU';
如果可能,请阅读 my answer for more understanding of my solution
最佳答案
ORA-01000,最大开放游标错误,是Oracle数据库开发中极其常见的错误。在 Java 上下文中,当应用程序尝试打开的 ResultSet 比数据库实例上配置的游标数多时,就会发生这种情况。
常见原因有:
背景
本节描述了游标背后的一些理论以及应该如何使用 JDBC。如果您不需要了解背景,则可以跳过此步骤并直接进入“消除泄漏”。
什么是游标?
游标是数据库上保存查询状态的资源,特别是读取器在 ResultSet 中的位置。每个 SELECT 语句都有一个游标,PL/SQL 存储过程可以根据需要打开和使用任意数量的游标。您可以在 Orafaq 上找到有关游标的更多信息.
一个数据库实例通常服务于几个不同的模式,许多不同的用户每个都有多个 session 。为此,它具有可用于所有模式、用户和 session 的固定数量的游标。当所有游标都打开(正在使用)并且请求需要新游标时,请求将失败并显示 ORA-010000 错误。
查找和设置光标数量
该编号通常由 DBA 在安装时配置。当前使用的游标数量、最大数量和配置可以在Oracle SQL Developer的管理员功能中访问。 .从 SQL 可以设置为:
ALTER SYSTEM SET OPEN_CURSORS=1337 SID='*' SCOPE=BOTH;
将 JVM 中的 JDBC 与 DB 上的游标相关联
下面的 JDBC 对象与以下数据库概念紧密耦合:
JDBC 是线程安全的:可以在线程之间传递各种 JDBC 对象。
例如,您可以在一个线程中创建连接;另一个线程可以使用此连接创建 PreparedStatement,第三个线程可以处理结果集。唯一的主要限制是在任何时候都不能在单个 PreparedStatement 上打开多个 ResultSet。见 Does Oracle DB support multiple (parallel) operations per connection?
请注意,数据库提交发生在连接上,因此该连接上的所有 DML(插入、更新和删除)将一起提交。因此,如果要同时支持多个事务,那么每个并发事务必须至少有一个Connection。
关闭 JDBC 对象
执行 ResultSet 的典型示例是:
Statement stmt = conn.createStatement();
try {
ResultSet rs = stmt.executeQuery( "SELECT FULL_NAME FROM EMP" );
try {
while ( rs.next() ) {
System.out.println( "Name: " + rs.getString("FULL_NAME") );
}
} finally {
try { rs.close(); } catch (Exception ignore) { }
}
} finally {
try { stmt.close(); } catch (Exception ignore) { }
}
请注意 finally 子句如何忽略 close() 引发的任何异常:
如果您有一个循环,例如,创建和执行语句,请记住关闭循环中的每个语句。
在 Java 7 中,Oracle 引入了 AutoCloseable interface它用一些不错的语法糖替换了大部分 Java 6 样板。
持有 JDBC 对象
JDBC 对象可以安全地保存在局部变量、对象实例和类成员中。通常更好的做法是:
但是,有一个异常(exception):如果您使用 EJB 或 Servlet/JSP 容器,则必须遵循严格的线程模型:
消除泄漏
有许多流程和工具可用于帮助检测和消除 JDBC 泄漏:
其他想法
你能用 WeakReferences 来处理关闭连接吗?
弱引用和软引用是允许您以允许 JVM 在其认为合适的任何时间对所指对象进行垃圾收集的方式来引用对象的方法(假设该对象没有强引用链)。
如果您在构造函数中将 ReferenceQueue 传递给软引用或弱引用,则当对象在发生时(如果它发生了)被 GC 处理时,该对象将被放置在 ReferenceQueue 中。使用这种方法,您可以与对象的终结进行交互,并且您可以在那一刻关闭或终结对象。
幻像引用有点奇怪;它们的目的只是控制终结,但你永远无法获得对原始对象的引用,因此很难对其调用 close() 方法。
但是,尝试控制何时运行 GC 很少是一个好主意(Weak、Soft 和 PhantomReferences 在对象已排队等待 GC 之后让您知道)。事实上,如果JVM中的内存量很大(例如-Xmx2000m),您可能永远不会对对象进行GC,您仍然会遇到ORA-01000。如果 JVM 内存相对于您的程序的要求来说很小,您可能会发现 ResultSet 和 PreparedStatement 对象在创建后立即被 GC 处理(在您可以读取它们之前),这可能会使您的程序失败。
TL;博士:弱引用机制不是管理和关闭 Statement 和 ResultSet 对象的好方法。
关于java.sql.SQLException : - ORA-01000: maximum open cursors exceeded,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12192592/