JDBC 框架

来源:互联网 发布:无锡知谷 拖欠 编辑:程序博客网 时间:2024/05/22 17:01

有两种方法可以实现对数据库统一的增删改查操作,一个是利用反射,一个是利用元数据。前者虽然实现简单,但是反射毕竟性能较低,不适合在移动设备上使用,下面我用两种方法实现 JDBC 的一个小框架。

 

一、利用反射技术

      思路分析:

                     我们对数据库的增删改查操作可以分为两类,一类是增删改即 update,一类是查询即 select。之所以这样分,是因为对数据库的增删改不需要涉及到 Bean 的操作,而查询就要分析我们要查询的对象。

                     首先我们考虑更新,我们需要用户将 sql 语句,参数传递给我们,然后我们可以利用 PreparedStatement 对象动态的将参数加入到预编译的 sql 中,这很简单,只需几行代码搞定,参数列表可以是数组,也可以是可变参。

                      查询操作我们除了需要知道上面的两个参数以外,还要知道我们操作的是什么 Bean,这也有两种方式,一种是让用户将 Bean 的 Class 字节码给我们,我们利用反射获取 Bean 里面的每一个字段,之后通过字段名内省出 Bean 的所有属性,从而达到将数据封装到 Bean 的效果。还有一种方式是用到策略模式,我们既然不知道要操作什么 Bean,那么我们就让用户来决定,我们只需要给用户暴露一个接口,将 ResultSet 传过去,用户就可以自己封装数据。为了简化用户操作,我们可以事先写好几个常用的实现类。下面我就演示如何用几行代码搞定增删改查操作:

public static <T> T crud(Class<?> type, String sql, Object... param) {Connection con = getConnection();PreparedStatement ps = null;ResultSet rs = null;T t = null;try {ps = con.prepareStatement(sql);for (int i = 1; param != null && i <= param.length; i++) {ps.setObject(i, param[i - 1]);}boolean execute = ps.execute();if (execute) {t = (T) type.newInstance();rs = ps.getResultSet();rs.next();Field[] fields = t.getClass().getDeclaredFields();for (int i = 0; i < fields.length; i++) {String fieldName = fields[i].getName();Object data = rs.getObject(fieldName);PropertyDescriptor descriptor = new PropertyDescriptor(fieldName, t.getClass());Method method = descriptor.getWriteMethod();method.invoke(t, data);}}} catch (Exception e) {throw new RuntimeException(e);} finally {release(con, ps, rs);}return t;}


 

 二、利用元数据

       思路分析:

                     上面的代码虽然简单,但是性能比较差,如果我们利用数据库元数据信息,就可以大大提升效率。至于数据库的元数据可以分为:DataBaseMetaData、ParameterMetaData、ResultSetMetaData。他们分别是数据库元数据,我们可以通过 DataBaseMetaData 获取与库相关的信息,比如 url、用户名、版本号、驱动名等等。ParameterMetaData 我们可以获取 sql 语句中的参数个数、参数类型。ResultSetMetaData 可以得到表的列数、指定列的名称、指定列的类型等。有了以上信息,我们为我们利用元数据实现 CRUD 很简单。这种方式我将利用策略模式实现。就是将封装数据的行为交给用户,当然,框架就是更方便的满足用户需求,我也将写两个实现类。

工具类:

package cn.dk.tools;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import com.mchange.v2.c3p0.ComboPooledDataSource;public class CrudTool {private static ComboPooledDataSource source = new ComboPooledDataSource("mysql");public static Connection getConnection() {try {return source.getConnection();} catch (Exception e) {throw new ExceptionInInitializerError(e);}}public static void release(Connection con, Statement st, ResultSet rs) {if (rs != null) {try {rs.close();} catch (SQLException e) {} finally {try {st.close();} catch (SQLException e) {} finally {try {st.close();} catch (SQLException e) {} finally {try {con.close();} catch (SQLException e) {}}}}}}public static int update(String sql, Object[] param) {Connection con = getConnection();PreparedStatement ps = null;try {ps = con.prepareStatement(sql);for (int i = 0; param != null && i < param.length; i++) {ps.setObject(i + 1, param[i]);}return ps.executeUpdate();} catch (SQLException e) {throw new RuntimeException(e);}}public static Object select(String sql, Object[] param,IResultSetHandler handler) {Connection con = getConnection();PreparedStatement ps = null;ResultSet rs = null;try {ps = con.prepareStatement(sql);for (int i = 0; param != null && i < param.length; i++) {ps.setObject(i + 1, param[i]);}rs = ps.executeQuery();return handler.fillObject(rs);} catch (SQLException e) {throw new RuntimeException(e);} finally {release(con, ps, rs);}}public static Number selectNum(String sql, Object[] param) {Connection con = getConnection();PreparedStatement ps = null;ResultSet rs = null;try {ps = con.prepareStatement(sql);for (int i = 0; param != null && i < param.length; i++) {ps.setObject(i + 1, param[i]);}rs = ps.executeQuery();if(rs.next())return (Number) rs.getObject(1);} catch (SQLException e) {throw new RuntimeException(e);} finally {release(con, ps, rs);}return 0;}}

 

实现类1:封装 Bean

package cn.dk.tools;import java.beans.PropertyDescriptor;import java.lang.reflect.Method;import java.sql.ResultSet;import java.sql.ResultSetMetaData;@SuppressWarnings("unchecked")public class BeanHandler implements IResultSetHandler {public BeanHandler(Class clazz) {this.clazz = clazz;}private Class clazz;public Object fillObject(ResultSet rs) {ResultSetMetaData metaData;try {Object instance = clazz.newInstance();if (rs != null && rs.next()) {metaData = rs.getMetaData();int columnCount = metaData.getColumnCount();for (int i = 0; i < columnCount; i++) {String propertyName = metaData.getColumnName(i + 1);Object object = rs.getObject(propertyName);PropertyDescriptor descriptor = new PropertyDescriptor(propertyName, clazz);Method writeMethod = descriptor.getWriteMethod();writeMethod.invoke(instance, object);}}return instance;} catch (Exception e) {throw new RuntimeException(e);}}}


实现类2:返回集合

package cn.dk.tools;import java.beans.PropertyDescriptor;import java.lang.reflect.Method;import java.sql.ResultSet;import java.sql.ResultSetMetaData;import java.util.ArrayList;import java.util.List;@SuppressWarnings("unchecked")public class BeanListHandler implements IResultSetHandler {public BeanListHandler(Class clazz) {this.clazz = clazz;}private Class clazz;public Object fillObject(ResultSet rs) {ResultSetMetaData metaData;try {List list = null;if (rs != null) {list = new ArrayList();while (rs.next()) {Object instance = clazz.newInstance();metaData = rs.getMetaData();int columnCount = metaData.getColumnCount();for (int i = 0; i < columnCount; i++) {String propertyName = metaData.getColumnName(i + 1);Object object = rs.getObject(propertyName);PropertyDescriptor descriptor = new PropertyDescriptor(propertyName, clazz);Method writeMethod = descriptor.getWriteMethod();writeMethod.invoke(instance, object);}list.add(instance);}}return list;} catch (Exception e) {throw new RuntimeException(e);}}}


      这种方法就给了我们一种思想,一种解决问题的思路。

 

原创粉丝点击