zoukankan      html  css  js  c++  java
  • 【总结】编写自己的JDBC框架

    一、数据库连接池: 

      在一般用JDBC 进行连接数据库进行CRUD操作时,每一次都会:

        通过:java.sql.Connection conn = DriverManager.getConnection(url,user,password); 重新获取一个数据库的链接再进行操作,这样用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。


          
            所以为了减少服务器的压力,便可用连接池的方法:在启动Web应用时,数据就创建好一定数量的Connection链接
      存放到一个容器中,然后当用户请求时,服务器则向容器中获取Connection链接来处理用户的请求,当用户的请求完成后,
      又将该Connection 链接放回到该容器中。这样的一个容器称为连接池。

        
      
      编写一个基本的连接池实现连接复用
           步骤:
           1、建立一个数据库连接池容器。(因为方便存取,则使用LinkedList集合)
           2、初始化一定数量的连接,放入到容器中。
           3、等待用户获取连接对象。(该部分要加锁)
              |---记得删除容器中对应的对象,放置别人同时获取到同一个对象。
           4、提供一个方法,回收用户用完的连接对象。
           5、要遵循先入先出的原则。

     1 import java.io.InputStream;
     2 import java.sql.Connection;
     3 import java.sql.DriverManager;
     4 import java.sql.SQLException;
     5 import java.util.LinkedList;
     6 import java.util.Properties;
     7 
     8 
     9 /**
    10  * 一个基本的数据连接池:  
    11  * 1、初始化时就建立一个容器,来存储一定数量的Connection 对象
    12  * 2、用户通过调用MyDataSource 的getConnection 来获取Connection 对象。
    13  * 3、再通过release 方法来回收Connection 对象,而不是直接关闭连接。
    14  * 4、遵守先进先出的原则。
    15  *  
    16  *     
    17  * @author 贺佐安
    18  *
    19  */
    20 public class MyDataSource {
    21     private static String url = null;
    22     private static String password = null;
    23     private static String user = null ;
    24     private static String DriverClass = null;
    25     private static LinkedList<Connection> pool = new LinkedList<Connection>() ;
    26 //    注册数据库驱动
    27     static {
    28         try {
    29             InputStream in = MyDataSource.class.getClassLoader()
    30                     .getResourceAsStream("db.properties");
    31             Properties prop = new Properties(); 
    32             prop.load(in);
    33             user = prop.getProperty("user"); 
    34             url = prop.getProperty("url") ;
    35             password = prop.getProperty("password") ; 
    36             DriverClass = prop.getProperty("DriverClass") ;  
    37             Class.forName(DriverClass) ;  
    38             
    39         } catch (Exception e) {
    40             throw new RuntimeException(e) ;
    41         }  
    42     }
    43     //初始化建立数据连接池
    44     public MyDataSource ()  {
    45         for(int i = 0 ; i < 10 ; i ++) {
    46             try {
    47                 Connection conn = DriverManager.getConnection(url, user, password) ;
    48                 pool.add(conn) ;
    49             } catch (SQLException e) {
    50                 e.printStackTrace();
    51             }
    52         }
    53     }
    54     //、从连接池获取连接
    55     public Connection getConnection() throws SQLException {
    56         return pool.remove() ;
    57     } 
    58     // 回收连接对象。
    59     public void release(Connection conn) {
    60         System.out.println(conn+"被回收");
    61         pool.addLast(conn) ;
    62     } 
    63     public int getLength() {
    64         return pool.size() ;
    65     }
    66 }

      这样当我们要使用Connection 连接数据库时,则可以直接使用连接池中Connection 的对象。测试如下:

     1 import java.sql.Connection;
     2 import java.sql.SQLException;
     3 
     4 import org.junit.Test;
     5 
     6 
     7 public class MyDataSourceTest {
     8     
     9     
    10     /**
    11      * 获取数据库连接池中的所有连接。
    12      */
    13     @Test
    14     public void Test() {
    15         MyDataSource mds = new MyDataSource() ; 
    16         Connection conn = null ;
    17         try {
    18             
    19             for (int i = 0 ; i < 20 ; i ++) {
    20                 conn = mds.getConnection() ;
    21                 System.out.println(conn+"被获取;连接池还有:"+mds.getLength()); 
    22                 mds.release(conn) ;
    23             } 
    24         } catch (SQLException e) {
    25             e.printStackTrace();
    26         } 
    27     }
    28 }

      再运行的时候,可以发现,循环10次后,又再一次获取到了第一次循环的得到的Connection对象。所以,这样可以大大的减轻数据库的压力。上面只是一个简单的数据库连接池,不完美的便是,回收需要调用数据池的release() 方法来进行回收,那么可以不可以直接调用Connection 实例的close 便完成Connection 对象的回收呢?


    二、数据源:  

        > 编写连接池需实现javax.sql.DataSource接口。
          > 实现DataSource接口,并实现连接池功能的步骤:
            1、在DataSource构造函数中批量创建与数据库的连接,并把创建的连接加入LinkedList对象中。

          2、实现getConnection方法,让getConnection方法每次调用时,从LinkedList中取一个Connection返回给用户。当用户使用完Connection,调用Connection.close()方法时,Collection对象应保证将自己返回到LinkedList中,而不要把conn还给数据库。

        利用动态代理和包装设计模式来标准的数据源。

        1、包装设计模式实现标准数据源:

          这里的用包装设计模式,便是将Connection 接口进行包装。简单总结一下包装设计模式的步骤:

              a)定义一个类,实现与被包装类()相同的接口。
                    |----可以先自己写一个适配器,然后后面继承这个适配器,改写需要改写的方法,提高编程效率。
                 b)定义一个实例变量,记住被包装类的对象的引用。
                 c)定义构造方法,转入被包装类的对象。

               e)对需要改写的方法,改写。
                        f)对不需要改写的方法,调用原来被包装类的对应方法。

          所以先编写一个类似适配器的类,将Connection 接口的方法都进行实现:

    import java.sql.Array;
    import java.sql.Blob;
    import java.sql.CallableStatement;
    import java.sql.Clob;
    import java.sql.Connection;
    import java.sql.DatabaseMetaData;
    import java.sql.NClob;
    import java.sql.PreparedStatement;
    import java.sql.SQLClientInfoException;
    import java.sql.SQLException;
    import java.sql.SQLWarning;
    import java.sql.SQLXML;
    import java.sql.Savepoint;
    import java.sql.Statement;
    import java.sql.Struct;
    import java.util.Map;
    import java.util.Properties;
    
    
    /**
     * 实现Connection 的适配器:
     * 目的:在使用包装设计模式时方便使用
     * @author 贺佐安
     *
     */
    
    public class MyConnectionAdapter implements Connection {
        //用一个实例变量,记住被包装类的实例引用
        protected Connection conn ;  
        //构造函数,转入被包装类的对象
        public MyConnectionAdapter(Connection conn) {
            this.conn = conn ;
        }
        @Override
        public <T> T unwrap(Class<T> iface) throws SQLException {
            return conn.unwrap(iface);
        }
        @Override
        public boolean isWrapperFor(Class<?> iface) throws SQLException {
            return conn.isWrapperFor(iface);
        }
        @Override
        public Statement createStatement() throws SQLException {
            return conn.createStatement();
        }
        @Override
        public PreparedStatement prepareStatement(String sql) throws SQLException {
            return conn.prepareStatement(sql);
        }
        @Override
        public CallableStatement prepareCall(String sql) throws SQLException {
            return conn.prepareCall(sql);
        }
        @Override
        public String nativeSQL(String sql) throws SQLException {
            return conn.nativeSQL(sql);
        }
        @Override
        public void setAutoCommit(boolean autoCommit) throws SQLException {
            conn.setAutoCommit(autoCommit);
        }
        @Override
        public boolean getAutoCommit() throws SQLException {
            return conn.getAutoCommit();
        }
        @Override
        public void commit() throws SQLException {
            conn.commit() ;
        }
        @Override
        public void rollback() throws SQLException {
            conn.rollback() ;
        }
        @Override
        public void close() throws SQLException {
            conn.close() ;
        }
        @Override
        public boolean isClosed() throws SQLException {
            return conn.isClosed();
        }
        @Override
        public DatabaseMetaData getMetaData() throws SQLException {
            return conn.getMetaData();
        }
        @Override
        public void setReadOnly(boolean readOnly) throws SQLException {
            conn.setReadOnly(readOnly);
        }
        @Override
        public boolean isReadOnly() throws SQLException {
            return conn.isReadOnly();
        }
        @Override
        public void setCatalog(String catalog) throws SQLException {
            conn.setCatalog(catalog) ;
        }
        @Override
        public String getCatalog() throws SQLException {
            return conn.getCatalog();
        }
        @Override
        public void setTransactionIsolation(int level) throws SQLException {
            conn.setTransactionIsolation(level) ;
        }
        @Override
        public int getTransactionIsolation() throws SQLException {
            return conn.getTransactionIsolation();
        }
        @Override
        public SQLWarning getWarnings() throws SQLException {
            return conn.getWarnings();
        }
        @Override
        public void clearWarnings() throws SQLException {
            conn.clearWarnings() ;
        }
        @Override
        public Statement createStatement(int resultSetType, int resultSetConcurrency)
                throws SQLException {
            return conn.createStatement(resultSetType, resultSetConcurrency);
            
        }
        @Override
        public PreparedStatement prepareStatement(String sql, int resultSetType,
                int resultSetConcurrency) throws SQLException {
            return conn.prepareStatement(sql, resultSetType, resultSetConcurrency);
        }
        @Override
        public CallableStatement prepareCall(String sql, int resultSetType,
                int resultSetConcurrency) throws SQLException {
            return conn.prepareCall(sql, resultSetType, resultSetConcurrency);
        }
        @Override
        public Map<String, Class<?>> getTypeMap() throws SQLException {
            return conn.getTypeMap();
        }
        @Override
        public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
            conn.setTypeMap(map) ;
        }
        @Override
        public void setHoldability(int holdability) throws SQLException {
            conn.setHoldability(holdability) ;
        }
        @Override
        public int getHoldability() throws SQLException {
            return conn.getHoldability();
        }
        @Override
        public Savepoint setSavepoint() throws SQLException {
            return conn.setSavepoint();
        }
        @Override
        public Savepoint setSavepoint(String name) throws SQLException {
            return conn.setSavepoint(name);
        }
        @Override
        public void rollback(Savepoint savepoint) throws SQLException {
            conn.rollback(savepoint);
        }
        @Override
        public void releaseSavepoint(Savepoint savepoint) throws SQLException {
            conn.releaseSavepoint(savepoint);
        }
        @Override
        public Statement createStatement(int resultSetType,
                int resultSetConcurrency, int resultSetHoldability)
                throws SQLException {
            return conn.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
        }
        @Override
        public PreparedStatement prepareStatement(String sql, int resultSetType,
                int resultSetConcurrency, int resultSetHoldability)
                throws SQLException {
            return conn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
        }
        @Override
        public CallableStatement prepareCall(String sql, int resultSetType,
                int resultSetConcurrency, int resultSetHoldability)
                throws SQLException {
            return conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
        }
        @Override
        public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
                throws SQLException {
            return conn.prepareStatement(sql, autoGeneratedKeys);
        }
        @Override
        public PreparedStatement prepareStatement(String sql, int[] columnIndexes)
                throws SQLException {
            return conn.prepareStatement(sql, columnIndexes);
        }
        @Override
        public PreparedStatement prepareStatement(String sql, String[] columnNames)
                throws SQLException {
            return conn.prepareStatement(sql, columnNames);
        }
        @Override
        public Clob createClob() throws SQLException {
            return conn.createClob();
        }
        @Override
        public Blob createBlob() throws SQLException {
            return conn.createBlob();
        }
        @Override
        public NClob createNClob() throws SQLException {
            return conn.createNClob();
        }
        @Override
        public SQLXML createSQLXML() throws SQLException {
            return conn.createSQLXML();
        }
        @Override
        public boolean isValid(int timeout) throws SQLException {
            return conn.isValid(timeout);
        }
        @Override
        public void setClientInfo(String name, String value)
                throws SQLClientInfoException {
            conn.setClientInfo(name, value) ;
        }
        @Override
        public void setClientInfo(Properties properties)
                throws SQLClientInfoException {
            conn.setClientInfo(properties) ;
        }
        @Override
        public String getClientInfo(String name) throws SQLException {
            return conn.getClientInfo(name);
        }
        @Override
        public Properties getClientInfo() throws SQLException {
            return conn.getClientInfo();
        }
        @Override
        public Array createArrayOf(String typeName, Object[] elements)
                throws SQLException {
            return conn.createArrayOf(typeName, elements);
        }
        @Override
        public Struct createStruct(String typeName, Object[] attributes)
                throws SQLException {
            return conn.createStruct(typeName, attributes);
        }
     
    }
    View Code

          然后再对Connection 接口进行包装,将close 方法修改掉:

     1 import java.sql.Connection;
     2 import java.sql.SQLException;
     3 import java.util.LinkedList;
     4 /**
     5  * 对MyConnectionAdapter 进行包装处理 
     6  * @author 贺佐安
     7  *
     8  */
     9 public class MyConnectionWrap extends MyConnectionAdapter {
    10 
    11     private LinkedList<Connection> pool = new LinkedList<Connection>() ;
    12     public MyConnectionWrap(Connection conn ,LinkedList<Connection> pool ) {
    13         super(conn); 
    14         this.pool = pool ; 
    15     }
    16     
    17     //改写要实现的方法
    18     public void close() throws SQLException {
    19         pool.addLast(conn) ;
    20     }
    21 }

          编写标准数据源:

      1 import java.io.PrintWriter;
      2 import java.sql.Connection;
      3 import java.sql.DriverManager;
      4 import java.sql.SQLException;
      5 import java.util.LinkedList;
      6 import java.util.ResourceBundle;
      7 
      8 import javax.sql.DataSource;
      9 
     10 
     11 /** 
     12  * 编写标准的数据源:
     13  * 1、实现DataSource 接口
     14  * 2、获取在实现类的构造方法中批量获取Connection 对象,并将这些Connection 存储
     15  * 在LinkedList 容器中。
     16  * 3、实现getConnection() 方法,调用时返回LinkedList容器的Connection对象给用户。
     17  * @author 贺佐安
     18  *
     19  */
     20 public class MyDataSource implements DataSource{
     21     private static String url = null;
     22     private static String password = null;
     23     private static String user = null ;
     24     private static String DriverClass = null;
     25     private static LinkedList<Connection> pool = new LinkedList<Connection>() ;
     26 
     27     //    注册数据库驱动
     28     static {
     29         try {  
     30             ResourceBundle rb = ResourceBundle.getBundle("db") ;
     31             url = rb.getString("url") ; 
     32             password = rb.getString("password") ; 
     33             user = rb.getString("user") ; 
     34             DriverClass = rb.getString("DriverClass") ;
     35             Class.forName(DriverClass) ;  
     36             
     37             //初始化建立数据连接池
     38             for(int i = 0 ; i < 10 ; i ++) {
     39                 Connection conn = DriverManager.getConnection(url, user, password) ;
     40                 pool.add(conn) ;
     41             }
     42         } catch (Exception e) {
     43             throw new RuntimeException(e) ;
     44         } 
     45         
     46     }
     47     public MyDataSource ()  {  
     48     }
     49     
     50     //、从连接池获取连接:通过包装模式
     51     public synchronized Connection getConnection() throws SQLException {
     52         if (pool.size() > 0) {
     53             MyConnectionWrap mcw = new MyConnectionWrap(pool.remove(), pool) ;
     54             return mcw ;
     55         }else {
     56             throw new RuntimeException("服务器繁忙!"); 
     57         }
     58     }
     59     
     60     // 回收连接对象。
     61     public void release(Connection conn) {
     62         System.out.println(conn+"被回收");
     63         pool.addLast(conn) ;
     64     }
     65     
     66     public int getLength() {
     67         return pool.size() ;
     68     }
     69     
     70     
     71     @Override
     72     public PrintWriter getLogWriter() throws SQLException {
     73         return null;
     74     }
     75     @Override
     76     public void setLogWriter(PrintWriter out) throws SQLException {
     77         
     78     }
     79     @Override
     80     public void setLoginTimeout(int seconds) throws SQLException {
     81         
     82     }
     83     @Override
     84     public int getLoginTimeout() throws SQLException {
     85         return 0;
     86     }
     87     @Override
     88     public <T> T unwrap(Class<T> iface) throws SQLException {
     89         return null;
     90     }
     91     @Override
     92     public boolean isWrapperFor(Class<?> iface) throws SQLException {
     93         return false;
     94     }
     95     @Override
     96     public Connection getConnection(String username, String password)
     97             throws SQLException {
     98         return null;
     99     }
    100     
    101 }

      2、动态代理实现标准数据源:

        相对于用包装设计来完成标准数据源,用动态代理则方便许多:

      

      1 import java.io.PrintWriter;
      2 import java.lang.reflect.InvocationHandler;
      3 import java.lang.reflect.Method;
      4 import java.lang.reflect.Proxy;
      5 import java.sql.Connection;
      6 import java.sql.DriverManager;
      7 import java.sql.SQLException;
      8 import java.util.LinkedList;
      9 import java.util.ResourceBundle;
     10 
     11 import javax.sql.DataSource;
     12 
     13 
     14 /** 
     15  * 编写标准的数据源:
     16  * 1、实现DataSource 接口
     17  * 2、获取在实现类的构造方法中批量获取Connection 对象,并将这些Connection 存储
     18  * 在LinkedList 容器中。
     19  * 3、实现getConnection() 方法,调用时返回LinkedList容器的Connection对象给用户。
     20  * @author 贺佐安
     21  *
     22  */
     23 public class MyDataSource implements DataSource{
     24     private static String url = null;
     25     private static String password = null;
     26     private static String user = null ;
     27     private static String DriverClass = null;
     28     private static LinkedList<Connection> pool = new LinkedList<Connection>() ;
     29 
     30     //    注册数据库驱动
     31     static {
     32         try {  
     33             ResourceBundle rb = ResourceBundle.getBundle("db") ;
     34             url = rb.getString("url") ; 
     35             password = rb.getString("password") ; 
     36             user = rb.getString("user") ; 
     37             DriverClass = rb.getString("DriverClass") ;
     38             Class.forName(DriverClass) ;  
     39             
     40             //初始化建立数据连接池
     41             for(int i = 0 ; i < 10 ; i ++) {
     42                 Connection conn = DriverManager.getConnection(url, user, password) ;
     43                 pool.add(conn) ;
     44             }
     45         } catch (Exception e) {
     46             throw new RuntimeException(e) ;
     47         }  
     48     }
     49     public MyDataSource ()  { 
     50         
     51     }
     52     
     53     //、从连接池获取连接:通过动态代理
     54     public Connection getConnection() throws SQLException {
     55         if (pool.size() > 0) {
     56             final Connection conn  = pool.remove() ; 
     57             Connection proxyCon = (Connection) Proxy.newProxyInstance(conn.getClass().getClassLoader(), conn.getClass().getInterfaces(), 
     58                     new InvocationHandler() {
     59                         //策略设计模式:
     60                         @Override
     61                         public Object invoke(Object proxy, Method method, Object[] args)
     62                                 throws Throwable {
     63                             if("close".equals(method.getName())){
     64                                 //谁调用,
     65                                 return pool.add(conn);//当调用close方法时,拦截了,把链接放回池中了
     66                             }else{
     67                                 return method.invoke(conn, args);
     68                             } 
     69                         }
     70                     });
     71           return proxyCon ;
     72         }else {
     73             throw new RuntimeException("服务器繁忙!"); 
     74         }
     75     } 
     76     
     77     public int getLength() {
     78         return pool.size() ;
     79     }
     80     
     81     
     82     @Override
     83     public PrintWriter getLogWriter() throws SQLException {
     84         return null;
     85     }
     86     @Override
     87     public void setLogWriter(PrintWriter out) throws SQLException {
     88         
     89     }
     90     @Override
     91     public void setLoginTimeout(int seconds) throws SQLException {
     92         
     93     }
     94     @Override
     95     public int getLoginTimeout() throws SQLException {
     96         return 0;
     97     }
     98     @Override
     99     public <T> T unwrap(Class<T> iface) throws SQLException {
    100         return null;
    101     }
    102     @Override
    103     public boolean isWrapperFor(Class<?> iface) throws SQLException {
    104         return false;
    105     }
    106     @Override
    107     public Connection getConnection(String username, String password)
    108             throws SQLException {
    109         return null;
    110     } 
    111 }

        当然觉得麻烦的则可以直接使用一些开源的数据源如:DBCP、C3P0等。DBCP的原理是用包装设计模式开发的数据源,而C3P0则是动态代理的。

        1、DBCP的使用:

     1 import java.io.InputStream;
     2 import java.sql.Connection;
     3 import java.sql.SQLException;
     4 import java.util.Properties;
     5 
     6 import javax.sql.DataSource;
     7 
     8 import org.apache.commons.dbcp.BasicDataSourceFactory;
     9 
    10 /**
    11  * 创建DBCP 工具类
    12  * @author 贺佐安
    13  *
    14  */
    15 public class DbcpUtil {
    16     private static DataSource ds = null ;
    17     static {
    18         try {
    19             //读取配置文件
    20             InputStream in = DbcpUtil.class.getClassLoader().getResourceAsStream("dbcpconfig.properties") ;
    21             Properties prop = new Properties() ; 
    22             prop.load(in) ;
    23             
    24             //通过BasicDataSourceFactory 的creatDataSurce 方法创建 BasicDataSource 对象。
    25             ds = BasicDataSourceFactory.createDataSource(prop) ;
    26             
    27         } catch (Exception e) {
    28             e.printStackTrace();
    29         } 
    30     }
    31     public static DataSource getDs() {
    32         return ds ; 
    33     }
    34     public static Connection getConnection () {
    35         try { 
    36             return ds.getConnection() ;
    37         } catch (SQLException e) {
    38             throw new RuntimeException() ;
    39         } 
    40     }
    41 }

        2、C3P0 的使用:

     1 import java.sql.Connection;
     2 import java.sql.SQLException;
     3 
     4 import com.mchange.v2.c3p0.ComboPooledDataSource;
     5 /**
     6  * C3P0 开源数据源的使用
     7  * @author 贺佐安
     8  *
     9  */
    10 public class C3p0Util {
    11     private static ComboPooledDataSource cpds  = null ;
    12     static {
    13         
    14         cpds = new ComboPooledDataSource() ; 
    15     }
    16     public static Connection getConnection() {
    17         try {
    18             return cpds.getConnection() ;
    19         } catch (SQLException e) {
    20             throw new RuntimeException() ;
    21         }
    22     }
    23 }

      使用这两个数据源时,直接调用获取到的Connection 连接的close 方法,也是将连接放到pool中去。

        

    三、元数据(DatabaseMetaData)信息的获取

      > 元数据:数据库、表、列的定义信息。    

      > 元数据信息的获取:为了编写JDBC框架使用。   

          1、数据库本身信息的获取:java.sql.DataBaseMateData java.sql.Connection.getMetaData() ;    

          DataBaseMateData 实现类的常用方法:    

            getURL():返回一个String类对象,代表数据库的URL。     

            getUserName():返回连接当前数据库管理系统的用户名。     

            getDatabaseProductName():返回数据库的产品名称。    

            getDatabaseProductVersion():返回数据库的版本号。     

            getDriverName():返回驱动驱动程序的名称。     

            getDriverVersion():返回驱动程序的版本号。    

            isReadOnly():返回一个boolean值,指示数据库是否只允许读操作。   

          2、ParameterMetaData: 代表PerparedStatment 中的SQL 参数元数据信息:    java.sql.ParameterMetaData java.sql.PerparedStatement.getParameterMetaData() ;          

          ParameterMetaData 实现类常用方法:     

            getParameterCount() :获得指定参数的个数    

            getParameterType(int param) :获得指定参数的sql类型(驱动可能不支持)

           3、ResultSetMetaData : 代表结果集的源数据信息:相当于SQL 中的 :DESC    java.sql.ResultSetMetaData java.sql.ResultSet.getMetaData() ;                

          java.sql.ResultSetMetaData 接口中常用的方法:     

            a) getColumnCount() : 获取查询方法有几列。     

            b) getColumnName(int index) : 获取列名:index从1开始。     

            c) getColumnType(int index) : 获取列的数据类型。返回的是TYPES  中的常量值。

    四、编写自己的JDBC框架:

        JDBC框架的基本组成:  

        1、核心类:

          a、定义一个指定javax.sql.DataSource 实例的引用变量,通过构造函数获取指定的实例并给定义的变量。
            b、编写SQL运行框架。

             DML 语句的编写:
                 1、通过获取的javax.sql.DataSource 实例,获取Connection 对象。
                 2、通过ParamenterMeteData 获取数据库元数据。
       
               DQL 语句的编写:
                 1、通过获取的DataSource 实例,获取Connection 对象。
                 2、通过ParamenterMeteData、ResultSetMetaData 等获取数据库元数据。
                 3、用抽象策略设计模式:设计一个ResultSetHandler 接口,作用:将查找出的数据封装到指定的JavaBean中。
                        |————这里的JavaBean,由用户来指定。
                        抽象策略模式,用户可以更具具体的功能来扩展成具体策略设计模式。如:查找的一条信息、查找的所有信息。

      1 import java.sql.Connection;
      2 import java.sql.ParameterMetaData;
      3 import java.sql.PreparedStatement;
      4 import java.sql.ResultSet;
      5 import java.sql.SQLException;
      6 import java.sql.Statement;
      7 
      8 import javax.sql.DataSource;
      9 
     10 /**
     11  * 实现JDBC 框架的核心类。
     12  * 在该类中定义了SQL语句完成的方法;
     13  * @author 贺佐安
     14  *
     15  */
     16 public class  MyJdbcFrame {
     17     /**
     18      * javax.sql.DataSource 实例的引用变量
     19      */
     20     private DataSource ds = null ;
     21     /**
     22      * 将用户指定的DataSource 指定给系统定义的DataSource 实例的引用变量
     23      * @param ds
     24      */
     25     public MyJdbcFrame(DataSource ds ) {
     26         this.ds = ds ; 
     27     }
     28     /**
     29      * 执行UPDATE、DELETE、INSERT 语句。
     30      * @param sql 
     31      * @param obj
     32      */
     33     public void update(String sql , Object[] obj) {
     34         Connection conn = null ; 
     35         PreparedStatement stmt = null ; 
     36         try {
     37             //获取Connection 对象
     38             conn = ds.getConnection() ;
     39             stmt = conn.prepareStatement(sql) ; 
     40             
     41             // 获取ParameterMetaData 元数据对象。
     42             ParameterMetaData pmd = stmt.getParameterMetaData() ;
     43             
     44             //获取SQL语句中需要设置的参数的个数
     45             int parameterCount = pmd.getParameterCount() ;
     46             if (parameterCount > 0) { 
     47                 if (obj == null || obj.length != parameterCount) {
     48                     throw new MyJdbcFrameException( "parameterCount is error!") ;
     49                 } 
     50                 //设置参数:
     51                 for ( int i = 0 ; i < obj.length ; i++) {
     52                     stmt.setObject(i+1, obj[i]) ;
     53                 }
     54             } 
     55             //执行语句:
     56             stmt.executeUpdate() ; 
     57             
     58         } catch(Exception e ) {
     59             throw new MyJdbcFrameException(e.getMessage()) ;
     60         } finally {
     61             release(stmt, null, conn) ;
     62         }
     63     }
     64     
     65     public Object query(String sql , Object[] obj , ResultSetHandler rsh) {
     66         Connection conn = null ; 
     67         PreparedStatement stmt = null ; 
     68         ResultSet rs = null ;
     69         try {
     70             //获取Connection 对象
     71             conn = ds.getConnection() ;
     72             stmt = conn.prepareStatement(sql) ; 
     73             
     74             // 获取ParameterMetaData 元数据对象。
     75             ParameterMetaData pmd = stmt.getParameterMetaData() ;
     76             
     77             //获取SQL语句中需要设置的参数的个数
     78             int parameterCount = pmd.getParameterCount() ;
     79             
     80             if (obj.length != parameterCount) {
     81                 throw new MyJdbcFrameException( "'" +sql +"' : parameterCount is error!") ;
     82             } 
     83             //设置参数:
     84             for ( int i = 0 ; i < obj.length ; i++) {
     85                 stmt.setObject(i+1, obj[i]) ;
     86             }
     87             //执行语句:
     88             rs = stmt.executeQuery(); 
     89             
     90             return rsh.handler(rs);
     91         } catch(Exception e ) {
     92             throw new MyJdbcFrameException(e.getMessage()) ;
     93         } finally {
     94             release(stmt, null, conn) ;
     95         } 
     96     } 
     97     /**
     98      * 释放资源
     99      * @param stmt
    100      * @param rs
    101      * @param conn
    102      */
    103     public static void release(Statement stmt 
    104                              , ResultSet rs 
    105                              , Connection conn) {
    106         if(rs != null) {
    107             try {
    108                 rs.close() ;
    109             } catch (SQLException e) {
    110                 e.printStackTrace();
    111             }
    112             rs = null ;
    113         }
    114         if (stmt != null) { 
    115             try {
    116                 stmt.close();
    117             } catch (SQLException e) {
    118                 e.printStackTrace();
    119             } 
    120             stmt = null ;
    121         }
    122         if (conn != null) {
    123             try {
    124                 conn.close();
    125             } catch (SQLException e) {
    126                 e.printStackTrace();
    127             }
    128             conn = null ;
    129         }
    130     } 
    131     
    132 }

        2、接口:策略模式的接口:ResultSetHandler

    1 import java.sql.ResultSet;
    2 
    3 //抽象策略模式
    4 public interface ResultSetHandler {
    5     public Object handler(ResultSet rs) ;
    6 }

        这里对ResultSetHandler 接口实现一个BeanHandler 实例 :

     1 import java.lang.reflect.Field;
     2 import java.sql.ResultSet;
     3 import java.sql.ResultSetMetaData;
     4 
     5 /**
     6  * 该类获取ResultSet 结果集中的第一个值,封装到JavaBean中
     7  * @author 贺佐安
     8  *
     9  */
    10 public class BeanHandler implements ResultSetHandler { 
    11     //获取要封装的JavaBean的字节码
    12     private Class clazz ;
    13     public BeanHandler (Class clazz) {
    14         this.clazz = clazz ;
    15     }
    16 
    17     public Object handler(ResultSet rs) {
    18         try {
    19             if (rs.next()) {
    20                 //1、获取结果集的元数据。
    21                 ResultSetMetaData rsm = rs.getMetaData() ;
    22                 //2、创建JavaBean的实例:
    23                 Object obj = clazz.newInstance() ;
    24                 //3、将数据封装到JavaBean中。  
    25                 for (int i = 0 ; i < rsm.getColumnCount() ; i ++) {
    26                     //获取属性名
    27                     String columnName = rsm.getColumnName(i+1) ; 
    28                     //获取属性值
    29                     Object value = rs.getObject(i+1) ; 
    30                     
    31                     Field objField = obj.getClass().getDeclaredField(columnName) ;
    32                     objField.setAccessible(true) ;
    33                     objField.set(obj, value) ;
    34                 }
    35                 return obj ;
    36             } else {
    37                 return null ;
    38             }
    39         } catch (Exception e) {
    40             throw new RuntimeException(e) ;
    41         }   
    42     } 
    43 }

        3、自定义异常类:继承RuntimeException。如:

    1 public class MyJdbcFrameException extends RuntimeException {
    2     public MyJdbcFrameException() {
    3         super() ; 
    4     }
    5     public MyJdbcFrameException(String e) {
    6         super(e) ;
    7     }
    8 }

        

      然后就可以将其打包发布,在以后写数据库操作时就可以用自己的JDBC框架了,如果要完成查询多条语句什么的,则要实现ResultSetHandler 接口。来完成更多的功能。

      当然,使用DBUtils 则更简单:Apache 组织提供的一个开源JDBC 工具类库。

        

     

    --------------------------------------------------------------------------------------学习时的总结。2013年7月18日 19:29:44

  • 相关阅读:
    Linux中几种常用的查看文件内容的命令(file,cat,more,less,head,tail)
    Linux 链接文件讲解
    postgreSQL psql工具使用详解
    将Redhat,CentOS,Ubuntu虚拟机的IP设为静态IP的方法
    Hive中的Order by与关系型数据库中的order by语句的异同点
    Hadoop namenode节点无法启动的问题解决
    虚拟机上的Ubuntu 文件系统成为只读模式的解决办法
    Hive参数的临时设置和永久性设置
    hive动态分区和混合分区
    MongoDB之Linux下的安装
  • 原文地址:https://www.cnblogs.com/jbelial/p/3199061.html
Copyright © 2011-2022 走看看