我收到了ORA-01000 SQL异常.所以我有一些与之相关的问题.
在循环中执行预准备语句会导致此问题吗?(当然,我本可以使用sqlBatch)注意:一旦循环结束,pStmt就会关闭.
{ //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
Run Code Online (Sandbox Code Playgroud)如果在单个连接对象上多次调用conn.createStatement()和conn.prepareStatement(sql)会发生什么?
Edit1: 6.使用Weak/Soft引用语句对象是否有助于防止泄漏?
Edit2: 1.有什么办法,我可以在项目中找到所有缺少的"statement.close()"吗?我知道这不是内存泄漏.但我需要找一个符合垃圾收集条件的语句引用(不执行close())?有什么工具可用?或者我必须手动分析它?
请帮我理解.
转到ORALCE机器并以sysdba启动sqlplus.
[oracle@db01 ~]$ sqlplus / as sysdba
Run Code Online (Sandbox Code Playgroud)
然后跑
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';
Run Code Online (Sandbox Code Playgroud)
如果可能的话,请在最后阅读我的答案.
And*_*ock 280
ORA-01000是最大打开游标错误,是Oracle数据库开发中极为常见的错误.在Java的上下文中,当应用程序尝试打开更多ResultSet而不是数据库实例上的已配置游标时,会发生这种情况.
常见原因是:
配置错误
光标泄漏
本节介绍了游标背后的一些理论以及如何使用JDBC.如果你不需要知道背景,你可以跳过这个并直接进入'消除泄漏'.
游标是数据库上保存查询状态的资源,特别是读者在ResultSet中的位置.每个SELECT语句都有一个游标,PL/SQL存储过程可以打开并使用所需数量的游标.您可以在Orafaq上找到有关游标的更多信息.
数据库实例通常提供多个不同的模式,许多不同的用户每个都有多个会话.为此,它具有可用于所有模式,用户和会话的固定数量的游标.当所有游标都打开(正在使用中)并且请求进入需要新游标时,请求将失败,并显示ORA-010000错误.
该号码通常由DBA在安装时配置.可以在Oracle SQL Developer的Administrator函数中访问当前使用的游标数,最大数量和配置.从SQL可以设置为:
ALTER SYSTEM SET OPEN_CURSORS=1337 SID='*' SCOPE=BOTH;
Run Code Online (Sandbox Code Playgroud)
下面的JDBC对象与以下数据库概念紧密耦合:
JDBC是线程安全的:在线程之间传递各种JDBC对象是完全可以的.
例如,您可以在一个线程中创建连接; 另一个线程可以使用此连接创建PreparedStatement,第三个线程可以处理结果集.唯一的主要限制是,您不能在任何时候在单个PreparedStatement上打开多个ResultSet.请参阅Oracle DB是否支持每个连接的多个(并行)操作?
请注意,数据库提交在Connection上发生,因此该连接上的所有DML(INSERT,UPDATE和DELETE)将一起提交.因此,如果要同时支持多个事务,则每个并发事务必须至少有一个Connection.
执行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) { }
}
Run Code Online (Sandbox Code Playgroud)
注意finally子句如何忽略close()引发的任何异常:
在Java 7中,Oracle引入了AutoCloseable接口,该接口用一些很好的语法糖取代了大部分Java 6样板.
JDBC对象可以安全地保存在局部变量,对象实例和类成员中.通常更好的做法是:
但是有一个例外:如果您使用的是EJB或Servlet/JSP容器,则必须遵循严格的线程模型:
有许多流程和工具可用于帮助检测和消除JDBC泄漏:
在开发过程中 - 早期捕获bug是迄今为止最好的方法:
在运行时:
可持续性和提交
在运行时记录.
您可以向项目添加调试JDBC驱动程序(用于调试 - 不实际部署它).一个例子(我没有用过它)是log4jdbc.然后,您需要对此文件进行一些简单的分析,以查看哪些执行没有相应的关闭.如果存在潜在问题,应该突出显示打开和关闭
弱引用和软引用是允许您以允许JVM在其认为合适的任何时间垃圾收集引用对象的方式引用对象的方式(假设该对象没有强引用链).
如果将构造函数中的ReferenceQueue传递给soft或weak Reference,则当对象发生GC时(如果它完全发生),该对象将被放置在ReferenceQueue中.使用此方法,您可以与对象的最终化进行交互,然后您可以在此时关闭或完成对象.
幽灵参考有点怪异; 他们的目的只是为了控制最终确定,但你永远无法得到原始对象的引用,所以这将是很难调用close()方法就可以了.
但是,尝试控制GC的运行时间很少是个好主意(Weak,Soft和PhantomReferences 会在对象排入GC 之后让您知道).事实上,如果在JVM的内存量较大(如-Xmx2000m),你可能永远不会 GC的对象,你还是会遇到ORA-01000.如果JVM内存相对于程序的要求很小,您可能会发现ResultSet和PreparedStatement对象在创建后立即被GCed(在您可以读取它们之前),这可能会使您的程序失败.
TL; DR:弱引用机制不是管理和关闭Statement和ResultSet对象的好方法.
Kan*_*mar 26
我增加了一些理解.
Loggin as sysdba.
在Putty(Oracle登录):
[oracle@db01 ~]$ sqlplus / as sysdba
Run Code Online (Sandbox Code Playgroud)
在SqlPlus中:
用户名: sys as sysdba
alter session set session_cached_cursors=0
select * from V$PARAMETER where name='session_cached_cursors'
Run Code Online (Sandbox Code Playgroud)
SELECT max(a.value) as highest_open_cur, p.value as max_open_cur FROM v$sesstat a, v$statname b, v$parameter p WHERE a.statistic# = b.statistic# AND b.name = 'opened cursors current' AND p.name= 'open_cursors' GROUP BY p.value;
Run Code Online (Sandbox Code Playgroud)
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 = 'SCHEMA_NAME_IN_CAPS'
Run Code Online (Sandbox Code Playgroud)
SELECT oc.sql_text, s.sid
FROM v$open_cursor oc, v$session s
WHERE OC.sid = S.sid
AND s.sid=1604
AND OC.USER_NAME ='SCHEMA_NAME_IN_CAPS'
Run Code Online (Sandbox Code Playgroud)
现在调试代码并享受!!! :)
像这样更正您的代码:
try
{ //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
{ //finally starts
pStmt.close()
}
Run Code Online (Sandbox Code Playgroud)
您确定您真的关闭了 pStatements、连接和结果吗?
要分析打开的对象,您可以实施委托模式,该模式将代码封装在您的声明、连接和结果对象周围。所以你会看到,如果一个对象将成功关闭。
示例:pStmt = obj。getConnection ().prepareStatement(sql);
class obj{
public Connection getConnection(){
return new ConnectionDelegator(...here create your connection object and put it into ...);
}
}
class ConnectionDelegator implements Connection{
Connection delegates;
public ConnectionDelegator(Connection con){
this.delegates = con;
}
public Statement prepareStatement(String sql){
return delegates.prepareStatement(sql);
}
public void close(){
try{
delegates.close();
}finally{
log.debug(delegates.toString() + " was closed");
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
306794 次 |
| 最近记录: |