【总结】编写自己的JDBC框架

时间:2023-03-09 09:49:06
【总结】编写自己的JDBC框架

一、数据库连接池:

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

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

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

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

 import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.Properties; /**
* 一个基本的数据连接池:
* 1、初始化时就建立一个容器,来存储一定数量的Connection 对象
* 2、用户通过调用MyDataSource 的getConnection 来获取Connection 对象。
* 3、再通过release 方法来回收Connection 对象,而不是直接关闭连接。
* 4、遵守先进先出的原则。
*
*
* @author 贺佐安
*
*/
public class MyDataSource {
private static String url = null;
private static String password = null;
private static String user = null ;
private static String DriverClass = null;
private static LinkedList<Connection> pool = new LinkedList<Connection>() ;
// 注册数据库驱动
static {
try {
InputStream in = MyDataSource.class.getClassLoader()
.getResourceAsStream("db.properties");
Properties prop = new Properties();
prop.load(in);
user = prop.getProperty("user");
url = prop.getProperty("url") ;
password = prop.getProperty("password") ;
DriverClass = prop.getProperty("DriverClass") ;
Class.forName(DriverClass) ; } catch (Exception e) {
throw new RuntimeException(e) ;
}
}
//初始化建立数据连接池
public MyDataSource () {
for(int i = 0 ; i < 10 ; i ++) {
try {
Connection conn = DriverManager.getConnection(url, user, password) ;
pool.add(conn) ;
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//、从连接池获取连接
public Connection getConnection() throws SQLException {
return pool.remove() ;
}
// 回收连接对象。
public void release(Connection conn) {
System.out.println(conn+"被回收");
pool.addLast(conn) ;
}
public int getLength() {
return pool.size() ;
}
}

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

 import java.sql.Connection;
import java.sql.SQLException; import org.junit.Test; public class MyDataSourceTest { /**
* 获取数据库连接池中的所有连接。
*/
@Test
public void Test() {
MyDataSource mds = new MyDataSource() ;
Connection conn = null ;
try { for (int i = 0 ; i < 20 ; i ++) {
conn = mds.getConnection() ;
System.out.println(conn+"被获取;连接池还有:"+mds.getLength());
mds.release(conn) ;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}

  再运行的时候,可以发现,循环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);
} }

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

 import java.sql.Connection;
import java.sql.SQLException;
import java.util.LinkedList;
/**
* 对MyConnectionAdapter 进行包装处理
* @author 贺佐安
*
*/
public class MyConnectionWrap extends MyConnectionAdapter { private LinkedList<Connection> pool = new LinkedList<Connection>() ;
public MyConnectionWrap(Connection conn ,LinkedList<Connection> pool ) {
super(conn);
this.pool = pool ;
} //改写要实现的方法
public void close() throws SQLException {
pool.addLast(conn) ;
}
}

      编写标准数据源:

 import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.ResourceBundle; import javax.sql.DataSource; /**
* 编写标准的数据源:
* 1、实现DataSource 接口
* 2、获取在实现类的构造方法中批量获取Connection 对象,并将这些Connection 存储
* 在LinkedList 容器中。
* 3、实现getConnection() 方法,调用时返回LinkedList容器的Connection对象给用户。
* @author 贺佐安
*
*/
public class MyDataSource implements DataSource{
private static String url = null;
private static String password = null;
private static String user = null ;
private static String DriverClass = null;
private static LinkedList<Connection> pool = new LinkedList<Connection>() ; // 注册数据库驱动
static {
try {
ResourceBundle rb = ResourceBundle.getBundle("db") ;
url = rb.getString("url") ;
password = rb.getString("password") ;
user = rb.getString("user") ;
DriverClass = rb.getString("DriverClass") ;
Class.forName(DriverClass) ; //初始化建立数据连接池
for(int i = 0 ; i < 10 ; i ++) {
Connection conn = DriverManager.getConnection(url, user, password) ;
pool.add(conn) ;
}
} catch (Exception e) {
throw new RuntimeException(e) ;
} }
public MyDataSource () {
} //、从连接池获取连接:通过包装模式
public synchronized Connection getConnection() throws SQLException {
if (pool.size() > 0) {
MyConnectionWrap mcw = new MyConnectionWrap(pool.remove(), pool) ;
return mcw ;
}else {
throw new RuntimeException("服务器繁忙!");
}
} // 回收连接对象。
public void release(Connection conn) {
System.out.println(conn+"被回收");
pool.addLast(conn) ;
} public int getLength() {
return pool.size() ;
} @Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException { }
@Override
public void setLoginTimeout(int seconds) throws SQLException { }
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
@Override
public Connection getConnection(String username, String password)
throws SQLException {
return null;
} }

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

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

  

 import java.io.PrintWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.ResourceBundle; import javax.sql.DataSource; /**
* 编写标准的数据源:
* 1、实现DataSource 接口
* 2、获取在实现类的构造方法中批量获取Connection 对象,并将这些Connection 存储
* 在LinkedList 容器中。
* 3、实现getConnection() 方法,调用时返回LinkedList容器的Connection对象给用户。
* @author 贺佐安
*
*/
public class MyDataSource implements DataSource{
private static String url = null;
private static String password = null;
private static String user = null ;
private static String DriverClass = null;
private static LinkedList<Connection> pool = new LinkedList<Connection>() ; // 注册数据库驱动
static {
try {
ResourceBundle rb = ResourceBundle.getBundle("db") ;
url = rb.getString("url") ;
password = rb.getString("password") ;
user = rb.getString("user") ;
DriverClass = rb.getString("DriverClass") ;
Class.forName(DriverClass) ; //初始化建立数据连接池
for(int i = 0 ; i < 10 ; i ++) {
Connection conn = DriverManager.getConnection(url, user, password) ;
pool.add(conn) ;
}
} catch (Exception e) {
throw new RuntimeException(e) ;
}
}
public MyDataSource () { } //、从连接池获取连接:通过动态代理
public Connection getConnection() throws SQLException {
if (pool.size() > 0) {
final Connection conn = pool.remove() ;
Connection proxyCon = (Connection) Proxy.newProxyInstance(conn.getClass().getClassLoader(), conn.getClass().getInterfaces(),
new InvocationHandler() {
//策略设计模式:
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if("close".equals(method.getName())){
//谁调用,
return pool.add(conn);//当调用close方法时,拦截了,把链接放回池中了
}else{
return method.invoke(conn, args);
}
}
});
return proxyCon ;
}else {
throw new RuntimeException("服务器繁忙!");
}
} public int getLength() {
return pool.size() ;
} @Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException { }
@Override
public void setLoginTimeout(int seconds) throws SQLException { }
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
@Override
public Connection getConnection(String username, String password)
throws SQLException {
return null;
}
}

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

    1、DBCP的使用:

 import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties; import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSourceFactory; /**
* 创建DBCP 工具类
* @author 贺佐安
*
*/
public class DbcpUtil {
private static DataSource ds = null ;
static {
try {
//读取配置文件
InputStream in = DbcpUtil.class.getClassLoader().getResourceAsStream("dbcpconfig.properties") ;
Properties prop = new Properties() ;
prop.load(in) ; //通过BasicDataSourceFactory 的creatDataSurce 方法创建 BasicDataSource 对象。
ds = BasicDataSourceFactory.createDataSource(prop) ; } catch (Exception e) {
e.printStackTrace();
}
}
public static DataSource getDs() {
return ds ;
}
public static Connection getConnection () {
try {
return ds.getConnection() ;
} catch (SQLException e) {
throw new RuntimeException() ;
}
}
}

    2、C3P0 的使用:

 import java.sql.Connection;
import java.sql.SQLException; import com.mchange.v2.c3p0.ComboPooledDataSource;
/**
* C3P0 开源数据源的使用
* @author 贺佐安
*
*/
public class C3p0Util {
private static ComboPooledDataSource cpds = null ;
static { cpds = new ComboPooledDataSource() ;
}
public static Connection getConnection() {
try {
return cpds.getConnection() ;
} catch (SQLException e) {
throw new RuntimeException() ;
}
}
}

  使用这两个数据源时,直接调用获取到的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,由用户来指定。
                    抽象策略模式,用户可以更具具体的功能来扩展成具体策略设计模式。如:查找的一条信息、查找的所有信息。

 import java.sql.Connection;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement; import javax.sql.DataSource; /**
* 实现JDBC 框架的核心类。
* 在该类中定义了SQL语句完成的方法;
* @author 贺佐安
*
*/
public class MyJdbcFrame {
/**
* javax.sql.DataSource 实例的引用变量
*/
private DataSource ds = null ;
/**
* 将用户指定的DataSource 指定给系统定义的DataSource 实例的引用变量
* @param ds
*/
public MyJdbcFrame(DataSource ds ) {
this.ds = ds ;
}
/**
* 执行UPDATE、DELETE、INSERT 语句。
* @param sql
* @param obj
*/
public void update(String sql , Object[] obj) {
Connection conn = null ;
PreparedStatement stmt = null ;
try {
//获取Connection 对象
conn = ds.getConnection() ;
stmt = conn.prepareStatement(sql) ; // 获取ParameterMetaData 元数据对象。
ParameterMetaData pmd = stmt.getParameterMetaData() ; //获取SQL语句中需要设置的参数的个数
int parameterCount = pmd.getParameterCount() ;
if (parameterCount > 0) {
if (obj == null || obj.length != parameterCount) {
throw new MyJdbcFrameException( "parameterCount is error!") ;
}
//设置参数:
for ( int i = 0 ; i < obj.length ; i++) {
stmt.setObject(i+1, obj[i]) ;
}
}
//执行语句:
stmt.executeUpdate() ; } catch(Exception e ) {
throw new MyJdbcFrameException(e.getMessage()) ;
} finally {
release(stmt, null, conn) ;
}
} public Object query(String sql , Object[] obj , ResultSetHandler rsh) {
Connection conn = null ;
PreparedStatement stmt = null ;
ResultSet rs = null ;
try {
//获取Connection 对象
conn = ds.getConnection() ;
stmt = conn.prepareStatement(sql) ; // 获取ParameterMetaData 元数据对象。
ParameterMetaData pmd = stmt.getParameterMetaData() ; //获取SQL语句中需要设置的参数的个数
int parameterCount = pmd.getParameterCount() ; if (obj.length != parameterCount) {
throw new MyJdbcFrameException( "'" +sql +"' : parameterCount is error!") ;
}
//设置参数:
for ( int i = 0 ; i < obj.length ; i++) {
stmt.setObject(i+1, obj[i]) ;
}
//执行语句:
rs = stmt.executeQuery(); return rsh.handler(rs);
} catch(Exception e ) {
throw new MyJdbcFrameException(e.getMessage()) ;
} finally {
release(stmt, null, conn) ;
}
}
/**
* 释放资源
* @param stmt
* @param rs
* @param conn
*/
public static void release(Statement stmt
, ResultSet rs
, Connection conn) {
if(rs != null) {
try {
rs.close() ;
} catch (SQLException e) {
e.printStackTrace();
}
rs = null ;
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
stmt = null ;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null ;
}
} }

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

 import java.sql.ResultSet;

 //抽象策略模式
public interface ResultSetHandler {
public Object handler(ResultSet rs) ;
}

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

 import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData; /**
* 该类获取ResultSet 结果集中的第一个值,封装到JavaBean中
* @author 贺佐安
*
*/
public class BeanHandler implements ResultSetHandler {
//获取要封装的JavaBean的字节码
private Class clazz ;
public BeanHandler (Class clazz) {
this.clazz = clazz ;
} public Object handler(ResultSet rs) {
try {
if (rs.next()) {
//1、获取结果集的元数据。
ResultSetMetaData rsm = rs.getMetaData() ;
//2、创建JavaBean的实例:
Object obj = clazz.newInstance() ;
//3、将数据封装到JavaBean中。
for (int i = 0 ; i < rsm.getColumnCount() ; i ++) {
//获取属性名
String columnName = rsm.getColumnName(i+1) ;
//获取属性值
Object value = rs.getObject(i+1) ; Field objField = obj.getClass().getDeclaredField(columnName) ;
objField.setAccessible(true) ;
objField.set(obj, value) ;
}
return obj ;
} else {
return null ;
}
} catch (Exception e) {
throw new RuntimeException(e) ;
}
}
}

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

 public class MyJdbcFrameException extends RuntimeException {
public MyJdbcFrameException() {
super() ;
}
public MyJdbcFrameException(String e) {
super(e) ;
}
}

    

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

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

    

 

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