zoukankan      html  css  js  c++  java
  • spring源码解读之 JdbcTemplate源码

    原文:https://blog.csdn.net/songjinbin/article/details/19857567

    在Spring中,JdbcTemplate是经常被使用的类来帮助用户程序操作数据库,在JdbcTemplate为用户程序提供了许多便利的数据库操作方法,比如查询,更新等,而且在Spring中,有许多类似 JdbcTemplate的模板,比如HibernateTemplate等等 - 看来这是Rod.Johnson的惯用手法,

        所谓模板板式,就是在父类中定义算法的主要流程,而把一些个性化的步骤延迟到子类中去实现,父类始终控制着整个流程的主动权,子类只是辅助父类实现某些可定制的步骤。 

    我们用代码来说话吧: 
    首先,父类要是个抽象类: 

    Java代码  

    public abstract class TemplatePattern {  
      
        //模板方法  
        public final void templateMethod(){  
              
            method1();  
            method2();//勾子方法  
            method3();//抽象方法  
        }  
        private void method1(){  
            System.out.println("父类实现业务逻辑");  
        }  
        public void method2(){  
            System.out.println("父类默认实现,子类可覆盖");  
        }  
        protected abstract void method3();//子类负责实现业务逻辑  
    }  


    父类中有三个方法,分别是method1(),method2()和method3()。 
    method1()是私有方法,有且只能由父类实现逻辑,由于方法是private的,所以只能父类调用。 
    method2()是所谓的勾子方法。父类提供默认实现,如果子类觉得有必要定制,则可以覆盖父类的默认实现。 
    method3()是子类必须实现的方法,即制定的步骤。 
    由此可看出,算法的流程执行顺序是由父类掌控的,子类只能配合。 

    下面我们来写第一个子类: 
    Java代码  

    public class TemplatePatternImpl extends TemplatePattern {  
      
        @Override  
        protected void method3() {  
            System.out.println("method3()在子类TemplatePatternImpl中实现了!!");  
      
        }  
      
    }  

    这个子类只覆盖了必须覆盖的方法,我们来测试一下: 
    Java代码  

    TemplatePattern t1 = new TemplatePatternImpl();  
    t1.templateMethod();  

    在控制台中我们可以看到: 
    Java代码  
    父类实现业务逻辑  
    父类默认实现,子类可覆盖  
    method3()在子类TemplatePatternImpl中实现了!!  


    OK,我们来看看勾子方法的使用: 
    定义第2个子类,实现勾子方法: 
    Java代码  

    public class TemplatePatternImpl2 extends TemplatePattern {  
      
        @Override  
        protected void method3() {  
            System.out.println("method3()在子类TemplatePatternImpl2中实现了!!");  
      
        }  
      
        /* (non-Javadoc) 
         * @see com.jak.pattern.template.example.TemplatePattern#method2() 
         */  
        @Override  
        public void method2() {  
            System.out.println("子类TemplatePatternImpl2覆盖了父类的method2()方法!!");  
        }  
          
    }  

    来测试一下: 
    Java代码  

    TemplatePattern t2 = new TemplatePatternImpl2();  
    t2.templateMethod();  

    我们看控制台: 
    Java代码  
    父类实现业务逻辑  
    子类TemplatePatternImpl2覆盖了父类的method2()方法!!  
    method3()在子类TemplatePatternImpl2中实现了!!  


    OK,经典的模板模式回顾完了(大家不要拍砖哦~~~~~~~~~~) 

    接下来,我们回到正题,自己模仿spring动手写一个基于模板模式和回调的jdbcTemplate。 

    回顾一下,spring为什么要封装JDBC API,对外提供jdbcTemplate呢(不要仍鸡蛋啊¥·%¥#%) 
    话说SUN的JDBC API也算是经典了,曾经在某个年代折服了一批人。但随着历史的发展,纯粹的JDBC API已经过于底层,而且不易控制,由开发人员直接接触JDBC API,会造成不可预知的风险。还有,数据连接缓存池的发展,也不可能让开发人员去手工获取JDBC了。 

    好了,我们来看一段曾经堪称经典的JDBC API代码吧: 
    Java代码  

    public List<User> query() {  
      
        List<User> userList = new ArrayList<User>();  
        String sql = "select * from User";  
      
        Connection con = null;  
        PreparedStatement pst = null;  
        ResultSet rs = null;  
        try {  
            con = HsqldbUtil.getConnection();  
            pst = con.prepareStatement(sql);  
            rs = pst.executeQuery();  
      
            User user = null;  
            while (rs.next()) {  
      
                user = new User();  
                user.setId(rs.getInt("id"));  
                user.setUserName(rs.getString("user_name"));  
                user.setBirth(rs.getDate("birth"));  
                user.setCreateDate(rs.getDate("create_date"));  
                userList.add(user);  
            }  
      
      
        } catch (SQLException e) {  
            e.printStackTrace();  
        }finally{  
            if(rs != null){  
                try {  
                    rs.close();  
                } catch (SQLException e) {  
                    e.printStackTrace();  
                }  
            }  
            try {  
                pst.close();  
            } catch (SQLException e) {  
                e.printStackTrace();  
            }  
            try {  
                if(!con.isClosed()){  
                    try {  
                        con.close();  
                    } catch (SQLException e) {  
                        e.printStackTrace();  
                    }  
                }  
            } catch (SQLException e) {  
                e.printStackTrace();  
            }  
              
        }  
        return userList;  
    }  

    上面的代码要若干年前可能是一段十分经典的,还可能被作为example被推广。但时过境迁,倘若哪位程序员现在再在自己的程序中出现以上代码,不是说明该公司的开发框架管理混乱,就说明这位程序员水平太“高”了。 
    我们试想,一个简单的查询,就要做这么一大堆事情,而且还要处理异常,我们不防来梳理一下: 
    1、获取connection 
    2、获取statement 
    3、获取resultset 
    4、遍历resultset并封装成集合 
    5、依次关闭connection,statement,resultset,而且还要考虑各种异常 
    6、..... 
    啊~~~~ 我快要晕了,在面向对象编程的年代里,这样的代码简直不能上人容忍。试想,上面我们只是做了一张表的查询,如果我们要做第2张表,第3张表呢,又是一堆重复的代码: 
    1、获取connection 
    2、获取statement 
    3、获取resultset 
    4、遍历resultset并封装成集合 
    5、依次关闭connection,statement,resultset,而且还要考虑各种异常 
    6、..... 

    这时候,使用模板模式的时机到了!!! 

    通过观察我们发现上面步骤中大多数都是重复的,可复用的,只有在遍历ResultSet并封装成集合的这一步骤是可定制的,因为每张表都映射不同的java bean。这部分代码是没有办法复用的,只能定制。那就让我们用一个抽象的父类把它们封装一下吧: 
    Java代码  

    public abstract class JdbcTemplate {  
      
        //template method  
        public final Object execute(String sql) throws SQLException{  
              
            Connection con = HsqldbUtil.getConnection();  
            Statement stmt = null;  
            try {  
       
                stmt = con.createStatement();  
                ResultSet rs = stmt.executeQuery(sql);  
                Object result = doInStatement(rs);//abstract method   
                return result;  
            }  
            catch (SQLException ex) {  
                 ex.printStackTrace();  
                 throw ex;  
            }  
            finally {  
       
                try {  
                    stmt.close();  
                } catch (SQLException e) {  
                    e.printStackTrace();  
                }  
                try {  
                    if(!con.isClosed()){  
                        try {  
                            con.close();  
                        } catch (SQLException e) {  
                            e.printStackTrace();  
                        }  
                    }  
                } catch (SQLException e) {  
                    e.printStackTrace();  
                }  
                  
            }  
        }  
          
        //implements in subclass  
        protected abstract Object doInStatement(ResultSet rs);  
    }  

    在上面这个抽象类中,封装了SUN JDBC API的主要流程,而遍历ResultSet这一步骤则放到抽象方法doInStatement()中,由子类负责实现。 
    好,我们来定义一个子类,并继承上面的父类: 
    Java代码  

    public class JdbcTemplateUserImpl extends JdbcTemplate {  
      
        @Override  
        protected Object doInStatement(ResultSet rs) {  
            List<User> userList = new ArrayList<User>();  
              
            try {  
                User user = null;  
                while (rs.next()) {  
      
                    user = new User();  
                    user.setId(rs.getInt("id"));  
                    user.setUserName(rs.getString("user_name"));  
                    user.setBirth(rs.getDate("birth"));  
                    user.setCreateDate(rs.getDate("create_date"));  
                    userList.add(user);  
                }  
                return userList;  
            } catch (SQLException e) {  
                e.printStackTrace();  
                return null;  
            }  
        }  
      
    }  

    由代码可见,我们在doInStatement()方法中,对ResultSet进行了遍历,最后并返回。 
    有人可能要问:我如何获取ResultSet 并传给doInStatement()方法啊??呵呵,问这个问题的大多是新手。因为此方法不是由子类调用的,而是由父类调用,并把ResultSet传递给子类的。我们来看一下测试代码: 
    Java代码  

    String sql = "select * from User";  
    JdbcTemplate jt = new JdbcTemplateUserImpl();  
    List<User> userList = (List<User>) jt.execute(sql); 

    就是这么简单!! 

    文章至此仿佛告一段落,莫急!不防让我们更深入一些... 

    试想,如果我每次用jdbcTemplate时,都要继承一下上面的父类,是不是有些不方面呢? 
    那就让我们甩掉abstract这顶帽子吧,这时,就该callback(回调)上场了 


    所谓回调,就是方法参数中传递一个接口,父类在调用此方法时,必须调用方法中传递的接口的实现类。 

    那我们就来把上面的代码改造一下,改用回调实现吧: 

    首先,我们来定义一个回调接口: 
    Java代码  

    public interface StatementCallback {  
        Object doInStatement(Statement stmt) throws SQLException;  
    }  

    这时候,我们就要方法的签名改一下了: 
    Java代码  

    private final Object execute(StatementCallback action) throws SQLException  

    里面的获取数据方式也要做如下修改: 
    Java代码  

    Object result = action.doInStatement(stmt);//abstract method   

    为了看着顺眼,我们来给他封装一层吧: 
    Java代码  

    public Object query(StatementCallback stmt) throws SQLException{  
        return execute(stmt);  
    }  

    OK,大功告成! 
    我们来写一个测试类Test.java测试一下吧: 
    这时候,访问有两种方式,一种是内部类的方式,一种是匿名方式。 

    先来看看内部类的方式: 
    Java代码  

    //内部类方式  
        public Object query(final String sql) throws SQLException {  
            class QueryStatementCallback implements StatementCallback {  
      
                public Object doInStatement(Statement stmt) throws SQLException {  
                    ResultSet rs = stmt.executeQuery(sql);  
                    List<User> userList = new ArrayList<User>();  
      
                    User user = null;  
                    while (rs.next()) {  
      
                        user = new User();  
                        user.setId(rs.getInt("id"));  
                        user.setUserName(rs.getString("user_name"));  
                        user.setBirth(rs.getDate("birth"));  
                        user.setCreateDate(rs.getDate("create_date"));  
                        userList.add(user);  
                    }  
                    return userList;  
      
                }  
      
            }  
      
            JdbcTemplate jt = new JdbcTemplate();  
            return jt.query(new QueryStatementCallback());  
        }  

    在调用jdbcTemplate.query()方法时,传一个StatementCallBack()的实例过去,也就是我们的内部类。 

    再来看看匿名方式: 
    Java代码  

    //匿名类方式  
        public Object query2(final String sql) throws Exception{  
              
            JdbcTemplate jt = new JdbcTemplate();  
            return jt.query(new StatementCallback() {  
                  
                public Object doInStatement(Statement stmt) throws SQLException {  
                    ResultSet rs = stmt.executeQuery(sql);  
                    List<User> userList = new ArrayList<User>();  
      
                    User user = null;  
                    while (rs.next()) {  
      
                        user = new User();  
                        user.setId(rs.getInt("id"));  
                        user.setUserName(rs.getString("user_name"));  
                        user.setBirth(rs.getDate("birth"));  
                        user.setCreateDate(rs.getDate("create_date"));  
                        userList.add(user);  
                    }  
                    return userList;  
      
                }  
            });  
              
        }  

    相比之下,这种方法更为简洁。 
    为什么spring不用传统的模板方法,而加之以Callback进行配合呢? 
    试想,如果父类中有10个抽象方法,而继承它的所有子类则要将这10个抽象方法全部实现,子类显得非常臃肿。而有时候某个子类只需要定制父类中的某一个方法该怎么办呢?这个时候就要用到Callback回调了。 

        最后的源码为:

    package com.jak.pattern.template.callbacktemplate;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    public interface StatementCallback {
        Object doInStatement(Statement stmt) throws SQLException;
    }
    public class JdbcTemplate {
        //template method
        private final Object execute(StatementCallback action) throws SQLException{    
        Connection con = HsqldbUtil.getConnection();
        Statement stmt = null;
      try {
          stmt = con.createStatement();
          Object result = action.doInStatement(stmt);//abstract method 
          return result;
      }
      catch (SQLException ex) {
        ex.printStackTrace();
        throw ex;
      }
      finally {
        try {
          stmt.close();
        } catch (SQLException e) {
          e.printStackTrace();
        }
        try {
          if(!con.isClosed()){
            try {
              con.close();
            } catch (SQLException e) {
              e.printStackTrace();
            }
          }
        } catch (SQLException e) {
          e.printStackTrace();
        }
      }
    }
    
      public Object query(StatementCallback stmt) throws SQLException{
    
    
      return execute(stmt);
      }
    }

    //调用测试类

    public class Test {
    
    //内部类方式
    public Object query(final String sql) throws SQLException {
    class QueryStatementCallback implements StatementCallback {
    
    public Object doInStatement(Statement stmt) throws SQLException {
        ResultSet rs = stmt.executeQuery(sql);
        List<User> userList = new ArrayList<User>();
    
        User user = null;
        while (rs.next()) {
    
            user = new User();
            user.setId(rs.getInt("id"));
            user.setUserName(rs.getString("user_name"));
            user.setBirth(rs.getDate("birth"));
            user.setCreateDate(rs.getDate("create_date"));
            userList.add(user);
        }
        return userList;
    
    }
    
    }
    
    JdbcTemplate jt = new JdbcTemplate();
        return jt.query(new QueryStatementCallback());
    }
    
    //匿名类方式
    public Object query2(final String sql) throws Exception{
    
        JdbcTemplate jt = new JdbcTemplate();
        return jt.query(new StatementCallback() {
    
    public Object doInStatement(Statement stmt) throws SQLException {
        ResultSet rs = stmt.executeQuery(sql);
        List<User> userList = new ArrayList<User>();
    
        User user = null;
        while (rs.next()) {
    
            user = new User();
            user.setId(rs.getInt("id"));
            user.setUserName(rs.getString("user_name"));
               user.setBirth(rs.getDate("birth"));
            user.setCreateDate(rs.getDate("create_date"));
            userList.add(user);
        }
        return userList;
    
        }
    });
    
    }
    public static void main(String[] args) throws Exception {
    
        String sql = "select * from User";
        Test t = new Test();
    
        List<User> userList = (List<User>) t.query(sql);
        List<User> userList2 = (List<User>) t.query2(sql);
        System.out.println(userList);
        System.out.println(userList2);
        }
    }                


    言归正传,有了上面的基础后,我们正式开始阅读源码:

    下面几个接口是对变化的部分进行建模


    接口:创建PreparedStatement。根据Connection来创建PreparedStatement。
     

    public interface PreparedStatementCreator {  
         PreparedStatement createPreparedStatement (Connection conn)  
           throws SQLException;  
       }  
    
        使用方法就是:
     
    PreparedStatementCreator psc = new PreparedStatementCreator() {  
      
         public PreparedStatement createPreparedStatement (Connection conn)  
             throws SQLException {  
           PreparedStatement ps = conn. prepareStatement (  
             "SELECT seat_id AS id FROM available_seats WHERE " +  
             "performance_id = ? AND price_band_id = ?");  
           ps.setInt(1, performanceId);  
           ps.setInt(2, seatType);  
           return ps;  
         }  
       };  

    给PreparedStatement设置参数。是对PreparedStatmentCreator的设置ps值的一个补充。

    public interface PreparedStatementSetter {  
        void setValues(PreparedStatement ps) throws SQLException;  
    }  

          

    对ResultSet进行处理。还有具体的子类。
     

    public interface RowCallbackHandler {  
         void processRow(ResultSet rs) throws SQLException;  
       }  

           使用方式:

     RowCallbackHandler rch = new RowCallbackHandler() {  
       public void processRow(ResultSet rs) throws SQLException {  
         int seatId = rs.getInt(1) ;  
         list.add(new Integer (seatId) );//典型的inner class的应用,list为外部类的变量。    
       }  
     };  

    和上面的RowCallbackHandler类似。
     

    public interface ResultSetExtractor {    
          Object extractData(ResultSet rs) throws SQLException, DataAccessException;    
    }   

          下面是JdbcTemplate中提供的模板方法。该方法完成对数据库的查询:)。

           这个execute()方法非常关键。
     

    public Object query(  
                PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor rse)  
                throws DataAccessException {  
      
            Assert.notNull(rse, "ResultSetExtractor must not be null");  
      
            if (logger.isDebugEnabled()) {  
                String sql = getSql(psc); //取得不变的SQL部分。 
                logger.debug("Executing SQL query" + (sql != null ? " [" + sql  + "]" : ""));  
            }  
            return execute(psc, new PreparedStatementCallback() {  
                public Object doInPreparedStatement(PreparedStatement ps) throws SQLException {  
                    ResultSet rs = null;  
                    try {  
                        if (pss != null) {  
                            pss.setValues(ps);//就是给ps来设置参数用的。ps.setInt(1, 0);  
                        }  
      
                        rs = ps.executeQuery();//执行查询  
      
                        ResultSet rsToUse = rs;  
                        if (nativeJdbcExtractor != null) {  
                            rsToUse = nativeJdbcExtractor.getNativeResultSet(rs);  
                        }  
                        return rse.extractData(rsToUse); // ResultSetExtractor从ResultSet中将值取出List。  
      
                    }  
                    finally {  
                        //最后的善后工作还是需要做好的:) rs.close(),把ps的相关参数清除掉。  
                        JdbcUtils.closeResultSet(rs);  
                        if (pss instanceof ParameterDisposer) {  
                            ((ParameterDisposer) pss).cleanupParameters();  
                        }  
                    }  
                }  
            });  
        }  

    看看execute()方法吧。
    java 代码
     

    public Object execute(PreparedStatementCreator psc, PreparedStatementCallback action)  
                throws DataAccessException {  
      
            Assert.notNull(psc, "PreparedStatementCreator must not be null");  
            Assert.notNull(action, "Callback object must not be null");  
      
            //取得数据库的连接  
            Connection con = DataSourceUtils.getConnection(getDataSource());  
            PreparedStatement ps = null;  
            try {  
                Connection conToUse = con;  
                if (this.nativeJdbcExtractor != null &&  
                        this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativePreparedStatements()) {  
                    conToUse = this.nativeJdbcExtractor.getNativeConnection(con);  
                }  
                //创建PreparedStatement  
                ps = psc.createPreparedStatement(conToUse);  
      
                applyStatementSettings(ps);//这个方法是设置ps的一些属性,我平时不用,Spring框架倒是考虑得相当全的说。  
                  
                PreparedStatement psToUse = ps;  
                if (this.nativeJdbcExtractor != null) {  
                    psToUse = this.nativeJdbcExtractor.getNativePreparedStatement(ps);  
                }  
                //调用Callback来完成PreparedStatement的设值。就是调用上面的doInPreparedStatement来使用ps。  
                Object result = action.doInPreparedStatement(psToUse);  
                
                SQLWarning warning = ps.getWarnings();  
                throwExceptionOnWarningIfNotIgnoringWarnings(warning);  
                return result;  
            }  
            //如果有错误的话,那么就开始ps.close(), connection.close();  
            catch (SQLException ex) {  
                // Release Connection early, to avoid potential connection pool deadlock  
                // in the case when the exception translator hasn't been initialized yet.  
                if (psc instanceof ParameterDisposer) {  
                    ((ParameterDisposer) psc).cleanupParameters();  
                }  
                String sql = getSql(psc);  
                psc = null;  
                JdbcUtils.closeStatement(ps);  //就是ps.close();
                ps = null;  
                DataSourceUtils.releaseConnection(con, getDataSource()); /  
                con = null;  
                throw getExceptionTranslator().translate("PreparedStatementCallback", sql, ex);  
            }  

            //不管怎么样,ps.close(), Connection.close()吧,当然这里是releaseConnection。在我的程序中,Connection只有一个,没有ConnectionPool,当然不会去close Connection。一般来讲,如果没有Connection的线程池的话,我们肯定也不会经常的关闭Connection,得到Connection。毕竟这个东西非常耗费资源。  

          

      finally {  
                if (psc instanceof ParameterDisposer) {  
                    ((ParameterDisposer) psc).cleanupParameters();  
                }  
                JdbcUtils.closeStatement(ps);  
                DataSourceUtils.releaseConnection(con, getDataSource());  
            }  
        }  

    JdbcTemplate完成了负责的操作,客户只需要调用query()就可以完成查询操作了。当然,JdbcTemplate会实现很多带其它参数的方法,以方便你的使用。Template设计模式被发扬广大了。
    DataSourceUtils:这个专门用于管理数据库Connection的类。

    public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {  
            try {  
                return doGetConnection(dataSource);  
                    ~~~~~~ //这个方法很舒服,Spring Framework中到处有这样的方法。为什么要委派到这个动作方法?  
            }  
            catch (SQLException ex) {  
                throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex);  
            }  
        }  

        这里的doGetConnection就稍微复杂一点了。但是如果没有事务同步管理器的话,那就比较简单。

    只是在Connection上多了一个ConnecionHolder类用于持有Connection,实现ConnectionPool的一点小功能。
     

    public static Connection doGetConnection(DataSource dataSource) throws SQLException {  
            Assert.notNull(dataSource, "No DataSource specified");  
      
            ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);  
            ~~~~~//Connection的持有器。通过持有器得到Connection。
            if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {  
                conHolder.requested();  
                if (!conHolder.hasConnection()) {  
                    logger.debug("Fetching resumed JDBC Connection from DataSource");  
                    conHolder.setConnection(dataSource.getConnection());  
                }  
                return conHolder.getConnection();  
            }  
            // Else we either got no holder or an empty thread-bound holder here.  
      
            logger.debug("Fetching JDBC Connection from DataSource");  
            Connection con = dataSource.getConnection();   
            ……
            return con;  
        }  
    
    ConnectionHolder:Connection的持有器。通过ConnectionHandler来完成对Connection的操作:) 典型的委派。
     
    public class ConnectionHolder extends ResourceHolderSupport {  
          
        private Connection currentConnection; //当前的Connection  
        private ConnectionHandle connectionHandle;  //Connection的处理器,因此可以通过该类完成对connection的管理。  
      
        public ConnectionHolder(Connection connection) {  
            this.connectionHandle = new SimpleConnectionHandle(connection);  
        }  
          
        public ConnectionHolder(ConnectionHandle connectionHandle) {  
            Assert.notNull(connectionHandle, "ConnectionHandle must not be null");  
            this.connectionHandle = connectionHandle;  
        }  
      
        public Connection getConnection() {  
            Assert.notNull(this.connectionHandle, "Active Connection is required");  
            if (this.currentConnection == null) {  
                this.currentConnection = this.connectionHandle.getConnection();  
            }  
            return this.currentConnection;  
        }  
      
        public void released() {  
            super.released();  
            if (this.currentConnection != null) {  
                this.connectionHandle.releaseConnection(this.currentConnection);  
                this.currentConnection = null;  
            }  
        }  
    
    connectionHandle 的接口太纯粹了。但是我觉得这个设计太过于细致了:) 
     
    public interface ConnectionHandle {  
      
        /** 
         * Fetch the JDBC Connection that this handle refers to. 
         */  
        Connection getConnection();  
      
        /** 
         * Release the JDBC Connection that this handle refers to. 
         * @param con the JDBC Connection to release 
         */  
        void releaseConnection(Connection con);  
      
    }  

      最后看一下SimpleConnectionHandle,这个ConnectionHandle的简单实现类。就只有一个Connection可管理。如果有多个Connection可管理的话,这里就是ConnectionPool了:)

    java 代码
     

    public class SimpleConnectionHandle implements ConnectionHandle {  
      
        private final Connection connection;  
      
      
        /** 
         * Create a new SimpleConnectionHandle for the given Connection. 
         * @param connection the JDBC Connection 
         */  
        public SimpleConnectionHandle(Connection connection) {  
            Assert.notNull(connection, "Connection must not be null");  
            this.connection = connection;  
        }  
      
        /** 
         * Return the specified Connection as-is. 
         */  
        public Connection getConnection() {  
            return connection;  
        }  
      
        /** 
         * This implementation is empty, as we're using a standard 
         * Connection handle that does not have to be released. 
         */  
        public void releaseConnection(Connection con) {  
        }  
      
      
        public String toString() {  
            return "SimpleConnectionHandle: " + this.connection;  
        }  
      
    }  
  • 相关阅读:
    vim 颜色主题设置
    给vim安装YouCompleteMe
    linux的主题与图标
    arch点击硬盘无法挂载
    arch安装完成之后不能使用笔记本自带的无线网卡
    curl的使用
    arch优化开机
    seo成功案例的背后秘密
    网站seo整站优化有什么优势
    企业站如何做长尾关键词seo优化
  • 原文地址:https://www.cnblogs.com/nxzblogs/p/10962959.html
Copyright © 2011-2022 走看看