最近在做的一个程序,遇到了一个JDBC方面的问题,我的代码如下
public ResultSet executeSql(String sqlstr)
{
Statement stmt = null;
ResultSet rs = null; try
{
stmt=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
rs=stmt.executeQuery(sqlstr);
DebugLog.logger.log(Level.INFO,"获取数据集成功");
return rs;
}
catch(SQLException e)
{
DebugLog.logger.log(Level.WARNING,"获取数据集时出现错误");
DebugLog.logger.log(Level.WARNING,e.getMessage());
try{
conn.rollback();
}
catch(SQLException i)
{
DebugLog.logger.log(Level.WARNING,"回滚数据集时出现错误");
DebugLog.logger.log(Level.WARNING,i.getMessage());
}
return null;
}
catch(Exception cnfe){
DebugLog.logger.log(Level.WARNING,"获取数据集时出现错误");
DebugLog.logger.log(Level.WARNING,cnfe.getMessage());
return null;
} }
这是我之前写的一段JDBC操作数据库的代码,但是主程序运行一段时间出现这样的异常ora-01000: maximum open cursors exceeded.到网上查了下,说是已经达到一个进程打开的最大游标数,Java代码在执行conn.createStatement()和conn.prepareStatement()的时候,实际上都是相当与在数据库中打开了一个cursor。
尤其是,如果你的createStatement和prepareStatement是在一个循环里面的话,就会非常容易出现这个问题。因为游标一直在不停的打开,而且没有关闭,所以说,最好在执行了一次executeQuery、executeUpdate等之后,如果不需要使用结果集(ResultSet)的数据,就马上将Statment关闭。然后我的代码改进如下
public ResultSet executeSql(String sqlstr)
{
Statement stmt = null;
ResultSet rs = null; try
{
stmt=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
rs=stmt.executeQuery(sqlstr);
DebugLog.logger.log(Level.INFO,"获取数据集成功");
return rs;
}
catch(SQLException e)
{
DebugLog.logger.log(Level.WARNING,"获取数据集时出现错误");
DebugLog.logger.log(Level.WARNING,e.getMessage());
try{
conn.rollback();
}
catch(SQLException i)
{
DebugLog.logger.log(Level.WARNING,"回滚数据集时出现错误");
DebugLog.logger.log(Level.WARNING,i.getMessage());
}
return null;
}
catch(Exception cnfe){
DebugLog.logger.log(Level.WARNING,"获取数据集时出现错误");
DebugLog.logger.log(Level.WARNING,cnfe.getMessage());
return null;
}finally{
try{
if(rs != null){
rs.close();
}
if(stmt != null){
stmt.close();
}
}catch(SQLException j){
DebugLog.logger.log(Level.WARNING,"关闭数据集时出现错误");
DebugLog.logger.log(Level.WARNING,j.getMessage());
}
}
}
但是这段代码的问题是,每次取这段代码执行SQL后返回的记录集,就会抛出一个信息为null的异常,我猜想是上面这个函数没返回任何记录集,rs是null的?
实在不知道什么原因,求高人指教,是什么原因?应该如何修改?谢谢了,我分不多,实在抱歉
public ResultSet executeSql(String sqlstr)
{
Statement stmt = null;
ResultSet rs = null; try
{
stmt=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
rs=stmt.executeQuery(sqlstr);
DebugLog.logger.log(Level.INFO,"获取数据集成功");
return rs;
}
catch(SQLException e)
{
DebugLog.logger.log(Level.WARNING,"获取数据集时出现错误");
DebugLog.logger.log(Level.WARNING,e.getMessage());
try{
conn.rollback();
}
catch(SQLException i)
{
DebugLog.logger.log(Level.WARNING,"回滚数据集时出现错误");
DebugLog.logger.log(Level.WARNING,i.getMessage());
}
return null;
}
catch(Exception cnfe){
DebugLog.logger.log(Level.WARNING,"获取数据集时出现错误");
DebugLog.logger.log(Level.WARNING,cnfe.getMessage());
return null;
} }
这是我之前写的一段JDBC操作数据库的代码,但是主程序运行一段时间出现这样的异常ora-01000: maximum open cursors exceeded.到网上查了下,说是已经达到一个进程打开的最大游标数,Java代码在执行conn.createStatement()和conn.prepareStatement()的时候,实际上都是相当与在数据库中打开了一个cursor。
尤其是,如果你的createStatement和prepareStatement是在一个循环里面的话,就会非常容易出现这个问题。因为游标一直在不停的打开,而且没有关闭,所以说,最好在执行了一次executeQuery、executeUpdate等之后,如果不需要使用结果集(ResultSet)的数据,就马上将Statment关闭。然后我的代码改进如下
public ResultSet executeSql(String sqlstr)
{
Statement stmt = null;
ResultSet rs = null; try
{
stmt=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
rs=stmt.executeQuery(sqlstr);
DebugLog.logger.log(Level.INFO,"获取数据集成功");
return rs;
}
catch(SQLException e)
{
DebugLog.logger.log(Level.WARNING,"获取数据集时出现错误");
DebugLog.logger.log(Level.WARNING,e.getMessage());
try{
conn.rollback();
}
catch(SQLException i)
{
DebugLog.logger.log(Level.WARNING,"回滚数据集时出现错误");
DebugLog.logger.log(Level.WARNING,i.getMessage());
}
return null;
}
catch(Exception cnfe){
DebugLog.logger.log(Level.WARNING,"获取数据集时出现错误");
DebugLog.logger.log(Level.WARNING,cnfe.getMessage());
return null;
}finally{
try{
if(rs != null){
rs.close();
}
if(stmt != null){
stmt.close();
}
}catch(SQLException j){
DebugLog.logger.log(Level.WARNING,"关闭数据集时出现错误");
DebugLog.logger.log(Level.WARNING,j.getMessage());
}
}
}
但是这段代码的问题是,每次取这段代码执行SQL后返回的记录集,就会抛出一个信息为null的异常,我猜想是上面这个函数没返回任何记录集,rs是null的?
实在不知道什么原因,求高人指教,是什么原因?应该如何修改?谢谢了,我分不多,实在抱歉
首先,在一个方法里面解决ResultSet的获取和关闭不是一个好选择,除非你使用其他东西(比如自己编写容器)缓存数据。因为关闭ResultSet导致结果集不能访问,关闭Statement也是一样。
其次,你的游标数越界,仅仅是因为你没有关闭Statement,而不是你没有“在这个方法里”关闭它。你完全可以在提取完ResultSet的数据后再关闭它。
第三,在你的第二个代码片段里,没有看到可以让返回值是null的地方,除了那个return null。不要受楼上lingkeylbh(凌可)的误导,java可没有那个本事。
恩,我试试在这个方法外面关闭它吧,不过因为每次打开都需要相应的关闭,所以我才那样写,不会遗漏关闭的问题
第三:我的说的出现信息为null的异常,倒不是这个函数的返回值是null,我的main 函数
public static void main(String[] args) {
// TODO Auto-generated method stub
ResultSet rs1;
int count = 0;
ConnDatabase sql1 = new ConnDatabase();
// sql1.ConnOracle();
sql1.ConnSqlServer();
// String sql;
sql1.ConnectThreeTimes();
// sql = "insert into tbl_eleccsss_v(Instruct_id,Srv_code,Id,Succ_flag,Err_msg,";
// sql+="Name,Descrb,Addr,Principal,Phone,Eye_count,Re,server_id,acc_id,cust_id)";
// sql+=" values(200062702,'000e',3,1,'error','dsf','fsddf','fsdf','fdf','50855657',32,'fds',324,'dsa',2556)";
//rs1=sql1.executeSql("select au_id,au_lname from authors");
// sql1.executeUpdate(sql);
rs1=sql1.executeSql("SELECT * FROM CSSSTOTELSMS");
//rs1=sql1.executeSql(sql);
try
{
while(rs1.next())
{
System.out.println(" ID: "+rs1.getString("ID")); }
}
catch(SQLException sqlex2) { System.out.println( ".mymethod - 不能关闭数据库连接: " + sqlex2.toString()); }
catch(Exception e)
{
System.out.println(e.getMessage());
} }
在这个主函数里,抛出了null的异常
连接池的connection的关闭只是将连接实例返回到连接池中
但是statment和resultset一定压迫关闭
因为这个和数据库连接的开销有关
如果你需要相关的数据,可以通过建立一个List
将需要的值拷贝到里面 然后关闭statment和resultset 返回呵呵 不过Hibernate有更好的解决方案忙 就说到这里了
rs3 = this.Conn1.executeSql(sql3);
try{
while(rs3.next()){
........
rs4 = this.Conn1.executeSql(sql4);
try{
while(rs4.next()){
.........
}catch(){
}
}
}catch(){
}
上面这段怎么关闭statment和resultset?其中this.Conn1是和一个数据库的连接,对这个数据库嵌套做了操作,如果里层的while(rs4.next())关闭了statment和resultset,会不会影响外层的while(rs3.next())而使外层的循环不能在继续了难道要解决这个问题只能改用连接池技术了,我到现在还没用过连接池呢,而且现在这个新业务除了现在这个问题外,就是运行时间长了会出现ora-01000: maximum open cursors exceeded.,业务处理上已经测试没什么问题了,改用连接池的话整个程序得大改了吧,不是还得重新测试?各位有没有更好的解决方法啊