【总结】编写自己的JDBC框架
一、数据库连接池:
在一般用JDBC 进行连接数据库进行CRUD操作时,每一次都会:
通过:java.sql.Connection conn = DriverManager.getConnection(url,user,password); 重新获取一个数据库的链接再进行操作,这样用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。
所以为了减少服务器的压力,便可用连接池的方法:在启动Web应用时,数据就创建好一定数量的Connection链接
存放到一个容器中,然后当用户请求时,服务器则向容器中获取Connection链接来处理用户的请求,当用户的请求完成后,
又将该Connection 链接放回到该容器中。这样的一个容器称为连接池。
编写一个基本的连接池实现连接复用
步骤:
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
【总结】编写自己的JDBC框架的更多相关文章
- javaweb学习总结(四十)——编写自己的JDBC框架
一.元数据介绍 元数据指的是"数据库"."表"."列"的定义信息. 1.1.DataBaseMetaData元数据 Connection.g ...
- 编写自定义的JDBC框架与策略模式
本篇根据上一篇利用数据库的几种元数据来仿造Apache公司的开源DbUtils工具类集合来编写自己的JDBC框架.也就是说在本篇中很大程度上的代码都和DbUtils中相似,学完本篇后即更容易了解DbU ...
- javaweb总结(四十)——编写自己的JDBC框架
一.元数据介绍 元数据指的是"数据库"."表"."列"的定义信息. 1.1.DataBaseMetaData元数据 Connection.g ...
- 编写自己的JDBC框架(转)
一.元数据介绍 元数据指的是"数据库"."表"."列"的定义信息. 1.1.DataBaseMetaData元数据 Connection.g ...
- java web学习总结(二十三) -------------------编写自己的JDBC框架
一.元数据介绍 元数据指的是"数据库"."表"."列"的定义信息. 1.1.DataBaseMetaData元数据 Connection.g ...
- JDBC 学习复习10 编写自己的JDBC框架
首先万分感谢狼哥 孤傲苍狼 博客,整个jdbc学习的博客资料 链接为http://www.cnblogs.com/xdp-gacl/p/4006830.html 详细代码见狼哥博客,列出我学习过程中遇 ...
- 编写自己的JDBC框架
目的 简化代码,提高开发效率 设计模式 策略设计模式 代码 #连接设置 driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost ...
- JDBC框架
一.元数据介绍 元数据指的是"数据库"."表"."列"的定义信息. 1.1.DataBaseMetaData元数据 Connection.g ...
- Spring的JDBC框架
转自: http://www.cnblogs.com/windlaughing/p/3287750.html Spring JDBC提供了一套JDBC抽象框架,用于简化JDBC开发. Spring主要 ...
随机推荐
- 在ios中使用第三方类库
在项目开发中经常会用到一些第三方类库,通常有两种方法来做到:一种方法是直接把所有的.h和.m文件复制到项目中:另一种方法是把.xcodeproj拖到项目中生成静态链接库并引用. 方法一:直接复制所有源 ...
- 我的Linux随笔目录
现在整理博客的时间少了,大多是在用为知笔记收藏和整理,一次集中发点Linux相关随笔整理和一个目录,是按时间顺序来的.每一篇都是自己用过之后整理的,应用场景已经尽可能的说明了,不明白的可以Q我,上班时 ...
- Dynamic CRM 2013学习笔记(十二)实现子表合计(汇总,求和)功能的通用插件
上一篇 Dynamic CRM 2013学习笔记(十一)利用Javascript实现子表合计(汇总,求和)功能 , 介绍了如何用js来实现子表合计功能,这种方法要求在各个表单上添加js方法,如果有很多 ...
- Vertica笔记
1.Table不做存储,本质是一个视图,真正存储在 Projection 里.可以针对一个Table建多个Projection . 查看表和 Projection 的个数: select anchor ...
- [ucgui] 对话框6——触屏位置简单例子
>_<:直接调用函数获得触屏位置: xPhys = GUI_TOUCH_GetxPhys(); /* Get the A/D mesurement result in x */ yPhys ...
- SharePoint API如何处理时区问题
使用SharePoint API,我们经常会有时区转换的问题,SharePoint API 本身如何处理时区问题的呢? 本文主要以Modified字段为例测试相关API的行为. CSOM API测试: ...
- SpringMVC从一个controller跳转到另一个controller
return "redirect:……路径……"; @RequestMapping(value = "/index", method = RequestMeth ...
- crossplatform---Node.js Applications with VS Code
Node.js is a platform for building fast and scalable server applications using JavaScript. Node.js i ...
- paip.语义相关是否可在 哈米 的语义分析中应用
paip.语义相关是否可在 哈米 的语义分析中应用 作者Attilax 艾龙, EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn. ...
- paip.判断文件是否存在uapi python php java c#
paip.判断文件是否存在uapi python php java c# ==========uapi file_exists exists() 面向对象风格: File.Exists 作者: 老哇 ...