小弟在一个系统里面有许多使用java查询sqlserver的地方。所以我写了下面几个类,感觉有些问题,想请教一下高人,欢迎大家指导。
下面我先介绍一下我的几个类,然后是代码示例。
(看在偶写了这么多的份上,希望能有高人愿意指点小弟一下,谢谢:)
===========================
下面共有三个类,connectdb,AutoMonitorDB,AutoMonitor
connectdb是链接数据库类,包含一个方法getConnection,其作用是从数据库中得到一个链接,并存储在成员变量conn,然后返回这个成员遍历。AutoMonitorDB类是封装了业务逻辑类AutoMonitor类中所有数据库操作方法的类。
   在构造类的时候得到connectdb类的实例。
   有一个ReleaseConn()方法,用来释放类成员变量中的链接的。
   还包含两个操作 
       GetRealRiverDataAndLevel() 返回一个ResultSet集合,共AutoMonitor类里面的方法使用。因为要返回ResultSet集合,所以不能关闭数据库链接。我的做法是在方法中使用AutoMonitorDB的成员变量的conn链接对象,AutoMonitor类中在使用完该函数返回的ResultSet集合后再调用AutoMonitorDB的ReleaseConn方法,释放AutoMonitorDB的成员变量链接conn。
       ChangeValleyAlarmInfo()方法是一个update操作,因为不用返回resultset集合,所以我在此方法中从成员connectionDB独立得到一个新的链接,使用完后再释放。   问题是在AutoMonitor类中某个方法当使用要上面类的第一个方法返回ResultSet后还没有调用ReleaseConn方法释放链接,就又需要调用AutoMonitorDB的其他方法,这样就又会创建新的链接。如果是ChangeValleyAlarmInfo()这一类的方法话,在调用后会释放链接。    我最初的想法是这样同时多个嵌套调用会申请多个链接,释放也会依次释放,应该没有问题。但现在webLogic总是报连接池没有释放链接。并且还存在ResultSet在使用时被关闭的问题。但我的代码也不是不能运行,在webLogic上一般都可以正常运行一段时间,只是报连接池的链接没有释放,被gc释放的warning。然后就会报一些链接不够,程序就开始出现问题。     我可以保证我的所以链接都对应有释放,并且都是finally里面。但很多申请和释放链接都是嵌套的(这就是我现在担心的地方)。
    
     有的朋友建议对DB类共用一个链接对象。也就时在AutoMonitorDB里面所有的操作都不申请也不释放链接,而是共用类成员变量里面的链接对象。然后在整个业务逻辑开始时初始化DB类,并为其申请一个链接。在最后释放掉这个链接,中间所有使用DB类的操作的时候都不释放链接。请问这种方法可行吗?
====================== =====public class connectdb {
    private Connection conn = null;    public Connection getConnection() {
        try {
            Context ctx = new InitialContext();
            javax.sql.DataSource ds = (javax.sql.DataSource) ctx.lookup("LYDS");
            conn = ds.getConnection();
        } catch (Exception e) {
            System.out.println(e.toString());
        }
        return conn;
    }
}
==================================================
public class AutoMonitorDB {
    private connectdb connectionDB;
    private Connection conn;
    private PreparedStatement ps;    public AutoMonitorDB() {
        connectionDB = new connectdb() ;
    }
    /**
     *
     * 释放类中的数据库链接
     *
     * @return 释放成功true ,异常false
     * */    public boolean ReleaseConn()    {
        try{
            if(ps!=null)
                ps.close() ;
            if(conn!=null)
                conn.close() ;
        }
        catch(Exception e){
            System.out.println(e.toString() );
            return false;
        }
        return true;
    }    /**
     *     
     * @return 的ResultSet集合
     * */
    public ResultSet GetRealRiverDataAndLevel() {
        conn = this.connectionDB.getConnection();
        ResultSet result = null;
        String sql;
        try {
            sql = "SELECT VNO FROM ST_WLVALUE_R,ST_WLSN";
            ps = conn.prepareStatement(sql);
            result = ps.executeQuery();
        } catch (Exception e) {
            System.out.println(e.toString());
            return null;
        }
        return result;
    }
    /**
     * 使用update语句操作数据库
     *
     * @param vno  流域编号
     * @param bj  要修改的新的报警级别
     * @return 成功true,失败false
     * * */
    public boolean ChangeValleyAlarmInfo(String vno) {
        Connection conn = this.connectionDB.getConnection();
        PreparedStatement ps = null;
        String sql;
        try {
            sql = "update TBL_VALLEYINFO where VNO = ?";
            ps = conn.prepareStatement(sql);
            ps.setString(1, vno);
            ps.execute();
        } catch (Exception e) {
            System.out.println(e.toString());
            return false;
        } finally {
            try {
                ps.close();
                conn.close();                
            } catch (Exception e1) {
                System.out.println(e1.toString());
            }
        }
        return true;
    }
}
=================================
public class AutoMonitor implements ActionListener {
    AutoMonitorDB am= new AutoMonitorDB() ;
    //使用AutoMonitorDB类的GetRealRiverDataAndLevel()函数,即使用ResultSet集合
    public void RainMonitor(){
        ResultSet rs = am.GetRealRiverDataAndLevel() ;
        try{
            while(rs.next() ){
                String valleyNo=rs.getString("VNO");
                //使用AutoMonitorDB类的ChangeValleyAlarmInfo函数
                boolean b=am.ChangeValleyAlarmInfo("aaa");
        }
        rs.close() ;        } catch (Exception e1) {
            System.out.println(e1.toString());
        } finally {
            am.ReleaseConn();
        }
    }
    
 

解决方案 »

  1.   

    代码只是释义性质的,像返回ResultSet集合类的方法我这里还有很多。大家就不用关心sql语句是否正确了。
      

  2.   

    你朋友的建议可以做,但是那只是我们在没有使用连接池的时候,并且不考虑大批量用户同时使用连接的情况下可行,如果每个人都用一个连接不释放,你想想100000个用户,甚至更多用户那将是一个什么概念,大量的浪费资源。而我们使用连接池机制就是为了解决这个问题。
       而你现在遇到的问题是有ResultSet结果集返回,所以连接不能及时关闭。所以我建议不要直接返回ResultSet结果集,这也是一个好习惯问题,所有数据库操作层使用的东西最好不要在业务层直接使用,我们可以把ResultSet结果集里的数据封装成数据对象,把数据对象存放在集合里,返回集合供业务层使用。我们要求在各个操作层之间传递的是对象,这也符合我们面向对象编程的思想。
      

  3.   

    恩把结果封装成WebRowSet
    连接的打开和关闭不要对外提供