简单JDBC封装类

fmms 10年前

为什么要做这个封装类:

以前经常使用Hibernate来操作数据库,但是时间长了以后发现,Hibernate的大多数功能其实我根本就用不上,而且,Hibernate的查询执行效率的确很让人纠结
所以,我又回到了JDBC的怀抱,而我又是个懒人,喜欢一个函数就能直接调用的那种,JDBC本身方法对我来说,要打的字太多了...@_@

 

入正题:

首先,画一个结构的草图

简单JDBC封装类

 

包结构:

简单JDBC封装类

先贴代码:

1.IConnectionProvider 接口

package org.sol.util.db;    import java.sql.Connection;  import java.sql.SQLException;    /**   * 用于获取连接的接口   * @author SOL   *   */  public interface IConnectionProvider {   public Connection getConnection(String sourceName) throws SQLException;  }
2.JDBCProvider JDBC数据提供源
package org.sol.util.db;    import java.sql.Connection;  import java.sql.DriverManager;  import java.sql.SQLException;    /**   * 标准JDBC连接获取代理   * @author HUYAO   *   */  public class JdbcProvider implements IConnectionProvider {   private String DBDriver;   private String DBUrl;   private String username;   private String password;      public JdbcProvider(String DBDriver,String DBUrl,String username,String password) throws ClassNotFoundException {    this.DBDriver = DBDriver;    this.DBUrl = DBUrl;    this.username = username;    this.password = password;        Class.forName(DBDriver);   }      @Override   public Connection getConnection(String sourceName) throws SQLException {    return DriverManager.getConnection(DBUrl + ";DatabaseName=" + sourceName,username,password);   }     public String getDBUrl() {    return DBUrl;   }     public void setDBUrl(String dBUrl) {    DBUrl = dBUrl;   }     public String getDBDriver() {    return DBDriver;   }     public String getUsername() {    return username;   }     public String getPassword() {    return password;   }     }
3.Tomcat数据提供源
package org.sol.util.db;    import java.sql.Connection;  import java.sql.SQLException;    import javax.naming.Context;  import javax.naming.InitialContext;  import javax.sql.DataSource;    /**   * TOMCAT JNDI连接池获取代理   * @author SOL   *   */  public class TomcatProvider implements IConnectionProvider {   @Override   public Connection getConnection(String sourceName) throws SQLException {    try {     Context ctx = new InitialContext();     return ((DataSource)ctx.lookup("java:comp/env/" + sourceName)).getConnection();    } catch (Exception e) {     throw new SQLException(e);    }   }  }
4.DataConsole 功能封装类
package org.sol.util.db;    import java.lang.reflect.Field;  import java.lang.reflect.InvocationTargetException;  import java.lang.reflect.Method;  import java.sql.CallableStatement;  import java.sql.Connection;  import java.sql.PreparedStatement;  import java.sql.ResultSet;  import java.sql.SQLException;  import java.sql.Statement;  import java.sql.Types;  import java.util.ArrayList;  import java.util.Arrays;  import java.util.HashMap;  import java.util.List;  import java.util.Map;  import java.util.Map.Entry;    import org.apache.commons.logging.Log;  import org.apache.commons.logging.LogFactory;    public class DataConsole {   /**    * 连接    */   private Connection connection;   /**    * 预处理对象    */   private PreparedStatement ps;   /**    * 存储过程处理对象    */   private CallableStatement cs;     /**    * 结果集对象    */   private ResultSet rs;   /**    * 数据源    */   private String sourceName;      /**    * 连接获取代理    */   private IConnectionProvider connectionProvider;     /**    * 事务超时事件    */   private int queryTime;      private static final Log log = LogFactory.getLog(DataConsole.class);      /**    * 生成一个JDBC封装对象    * @param connectionProvider 连接提供代理    * @param sourceName 数据源名称,connectionProvider根据此名称切换数据源    * @param queryTime 事务处理超时时间 0:无超时    */   public DataConsole(IConnectionProvider connectionProvider,String sourceName,int queryTime) {    this.connectionProvider = connectionProvider;    this.sourceName = sourceName;    this.queryTime = queryTime;   }      /**    * 统计语句查询 直接返回唯一值    * @param sql    * @param objs    * @return    * @throws SQLException    */   public Object findReturn(String sql,Object... objs) throws SQLException {    log.debug("Query return value:[" + sql + "] " + (objs != null ? Arrays.deepToString(objs) : ""));      try {     getConnection();          ps = connection.prepareStatement(sql);     ps.setQueryTimeout(queryTime);          if(objs != null) {      for(int i = 0 ; i < objs.length; i ++)       ps.setObject(i + 1, objs[i]);     }     rs = ps.executeQuery();     if(rs.next())      return rs.getObject(1);     else      return null;    } finally {     close();    }   }      /**    * 执行存储过程 首字段用于处理返回值 所以存储过程写法必须是 {?=call PRODUCENAME(?,?...,?)}    * @param call 存储过程    * @param returnType 返回参数类型 [Types.XXXX]    * @param objs 参数列表    * @return    * @throws SQLException    */   public Object callWithReturn(String call,int returnType,Object... objs) throws SQLException {    log.debug("Call return value:[" + call + "] " + (objs != null ? Arrays.deepToString(objs) : ""));    try {     getConnection();       cs = connection.prepareCall(call);     cs.setQueryTimeout(queryTime);          cs.registerOutParameter(1, returnType);     for(int i = 0; i < objs.length; i ++)      cs.setObject(i+2,objs[i]);          cs.execute();     return cs.getObject(1);    } finally {     close();    }   }      /**    * 用于执行返回列表的存储过程  并映射到对象列表上    * @param <X>     * @param clazz 映射对象    * @param sql 查询语句    * @param smap 映射配置表<字段名,类型>    * @param objs 参数列表    * @return    * @throws Exception    */   public <X> List<X> call(Class<X> clazz,String sql,Map<String,Class<?>> smap,Object... objs) throws Exception {    log.debug("Call Query produce:[" + sql + "] " + (objs != null ? Arrays.deepToString(objs) : ""));    try {     rs = call(sql, objs);          List<X> list = new ArrayList<X>();          while(rs != null && rs.next()) {      X obj = returnObject(clazz,smap);            list.add(obj);     }          return list;    } catch (Exception e) {     close();     throw e;    } finally {     close();    }   }      private ResultSet call(String sql,Object... params) throws SQLException {    getConnection();        cs = connection.prepareCall(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,      ResultSet.CONCUR_READ_ONLY);    cs.setQueryTimeout(queryTime);        cs.registerOutParameter(1, Types.REAL);    for(int i = 0; i < params.length; i ++)     cs.setObject(i + 2, params[i]);        return cs.executeQuery();   }      /**    * 查询单个对象 并映射到对象上    * @param <X>     * @param clazz 映射对象    * @param sql 查询语句    * @param smap 映射配置表<字段名,类型>    * @param objs 参数列表    * @return    * @throws Exception    */   public <X> X get(Class<X> clazz,String sql,Map<String,Class<?>> smap,Object... objs) throws SQLException {    log.debug("Get Entity:[" + sql + "] " + (objs != null ? Arrays.deepToString(objs) : ""));    try {     rs = query(sql, objs);          if(rs != null && rs.next()) {      X obj = returnObject(clazz,smap);            return obj;     } else {      return null;     }         } catch (Exception e) {     throw new SQLException(e);    } finally {     close();    }   }      private ResultSet query(String sql,Object... objs) throws Exception {    getConnection();      ps = connection.prepareStatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,      ResultSet.CONCUR_READ_ONLY);    ps.setQueryTimeout(queryTime);        if(objs != null) {     for(int i = 0; i < objs.length; i ++)      ps.setObject(i + 1, objs[i]);    }    return ps.executeQuery();   }   /**    * 用于解析查询结果 并映射到对象    * @param <X>    * @param clazz 映射对象    * @param smap 映射表    * @return    * @throws InstantiationException    * @throws SecurityException    * @throws NoSuchMethodException    * @throws SQLException    * @throws IllegalAccessException    */   private <X> X returnObject(Class<X> clazz,Map<String,Class<?>> smap) throws InstantiationException,  SecurityException, NoSuchMethodException, SQLException, IllegalAccessException {    X obj = clazz.newInstance();        for(Entry<String,Class<?>> en : smap.entrySet()) {     try {      Object value = rs.getObject(en.getKey());            setField(obj,en.getKey(),en.getValue(),(en.getValue().equals(String.class) ? (value != null ? value : null) : value));     } catch (IllegalArgumentException e1) {      log.error("不正确的对象映射. 映射类:" + clazz.getName() +         " 配置字段名:" + en.getKey() +         " 类型:" + en.getValue().getName() +         " 数据库字段类型:" + rs.getObject(en.getKey()).getClass().getName());     } catch (InvocationTargetException e1) {      e1.printStackTrace();     }    }        return obj;   }      /**    * 设置对象上字段的值    * 现在只支持简单的对象类型 String Integer Short Double 等标准对象    * 可以扩展这个方法用来支持一些比较复杂的对象格式    * @param obj 映射的对象    * @param fieldname 字段名称 将调用它的set方法进行设置    * @param type 字段类型    * @param value 字段值    * @throws SecurityException    * @throws NoSuchMethodException    * @throws IllegalArgumentException    * @throws IllegalAccessException    * @throws InvocationTargetException    */   protected void setField(Object obj,String fieldname,Class<?> type,Object value) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException  {    Method method = obj.getClass().getMethod(setMethod(fieldname),type);    method.invoke(obj, value);   }     /**    * 执行插入语句,并返回生成的主键    * @param sql 插入语句    * @param objs 参数列表    * @return 插入语句返回的主键值    * @throws SQLException    */   public int insertAndReturnKey(String sql,Object... objs) throws SQLException {    int countRow = 0;    int key = 0;        log.debug("Insert and return Id:[" + sql + "] " + (objs != null ? Arrays.deepToString(objs) : ""));    try {     getConnection();          connection.setAutoCommit(false);       ps = connection.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);     ps.setQueryTimeout(queryTime);          if(objs != null) {      for(int i = 0; i < objs.length; i ++)       ps.setObject(i+1,objs[i]);     }          countRow = ps.executeUpdate();     if(countRow > 0) {      ResultSet rs = ps.getGeneratedKeys();      if(rs.next())       key = rs.getInt(1);     }     connection.commit();    } catch (SQLException e) {     countRow = 0;     connection.rollback();     closeConnection();     throw e;    } finally {     if (connection != null) {      connection.setAutoCommit(true);     }     close();    }    return key;   }      /**    * 执行预编译SQL     * @param sql SQL语句    * @param objs 参数列表    * @return 执行影响条数    * @throws SQLException    */   public int updatePrepareSQL(String sql,Object... objs) throws SQLException {    log.debug("Update:[" + sql + "]" + (objs != null ? objs.toString() : ""));        int countRow = 0;    try {     getConnection();       connection.setAutoCommit(false);       ps = connection.prepareStatement(sql);     ps.setQueryTimeout(queryTime);     if(objs != null) {      for(int i = 0; i < objs.length; i ++)       ps.setObject(i+1,objs[i]);     }     countRow = ps.executeUpdate();     connection.commit();    } catch (SQLException e) {     countRow = 0;     connection.rollback();     closeConnection();     throw e;    } finally {     if (connection != null) {      connection.setAutoCommit(true);     }     close();    }    return countRow;   }     public <X> List<X> find(String sql,Class<X> clazz,Map<String,Class<?>> smap,Object... objs) throws SQLException {    try {     log.debug("Query:" + sql + " Class:" + clazz.getName() + (objs != null ? Arrays.deepToString(objs) : ""));          rs = query(sql, objs);          List<X> list = new ArrayList<X>();          while(rs != null && rs.next()) {      X obj = returnObject(clazz,smap);            list.add(obj);     }          return list;    } catch (Exception e) {     throw new SQLException(e);    } finally {     close();    }   }     public void closeConnection() {    try {     if (connection != null) {      connection.close();     }     connection = null;    } catch (Exception e) {    }   }      public Connection getConnection() throws SQLException {    if(sourceName == null)     throw new SQLException("没有设置数据源");        int Times = 0;    while (connection == null || connection.isClosed()) {     try {      closeConnection();      connection = connectionProvider.getConnection(sourceName);      break;     } catch (Exception sqle) {      log.error("error getConnection():" + sqle.getMessage(),sqle);     }finally{      if(Times>5){       throw new SQLException("获取连接次数已经超过6次。不再尝试重新获取");      }      ++Times;     }    }    return connection;   }      public void close() {    try {     super.finalize();     if (rs != null) {      rs.close();      rs = null;     }     if (ps != null) {      ps.close();      ps = null;     }     if (cs != null) {      cs.close();      cs = null;     }     if (connection != null) {      connection.close();      connection = null;     }    } catch (Throwable te) {    }   }     public static Map<String,Class<?>> parseSmap(Class<?> clazz,String... paramNames) {    Map<String,Class<?>> smap = new HashMap<String, Class<?>>(paramNames.length);        for(String name : paramNames) {     try {      Field field = clazz.getDeclaredField(name);      smap.put(name, field.getType());     } catch (Exception e) {      throw new RuntimeException(e);     }     }        return smap;   }      public static String getMethod(String name) {    return "get" + name.replaceFirst(name.substring(0,1), name.substring(0,1).toUpperCase());   }      public static String setMethod(String name) {    return "set" + name.replaceFirst(name.substring(0,1), name.substring(0,1).toUpperCase());   }  }
简单介绍一下这个封装类

封装类通过ConnectionProvider获取相应的数据源类型,提供几个快速使用的JDBC方法,包括查询,更新语句,插入并返回主键,调用存储过程等几个常用方法,可以看源文件里的说明

用一个测试类来说明吧

package org.sol.util.db;    import java.sql.SQLException;  import java.sql.Types;    public class test {   private IConnectionProvider connectionProvider = null;   private String sourceName = "megajoysms";   private int queryTime = 5;      private DataConsole dc;      public test() {    /*     * 首先建立数据源对象,现在演示的使用的是JDBC提供源     * 三个参数 1.驱动名称 2.url(数据库名不需要填写,由sourceName参数执行) 3.登录用户名 4.密码     * 代码中还提供了一个tomcat的jndi数据提供源,其他类似的源可以直接继承IConnectionProvider接口实现     */    try {     connectionProvider = new JdbcProvider(       "com.microsoft.sqlserver.jdbc.SQLServerDriver",        "jdbc:sqlserver://127.0.0.1:1433",       "sa","123456");    } catch (ClassNotFoundException e) {     e.printStackTrace();    }        dc = new DataConsole(connectionProvider, sourceName, queryTime);   }      /**    * Find 方法用来查询对象    * 接收3+ 个参数    * 第一个参数表示执行的Select语句    * 第二个参数表示查询结果映射到一个对象类型上    * 第三个参数表示对查询结果字段的映射关系    * 第四个字段用于如果SQL语句是带参数的,从这里开始填入变量列表    *     * 数据表test结构    * int id,    * varchar text,    * varchar value    * 映射对象结构    * class pojo {    private Integer id;    private String text;    get/set 方法...    }    * 第三个参数的类型是Map<String,Class<?>>表示 字段名-字段类型的映射关系    * 可以自己建立这个map,map的键用来匹配查询结果集的字段及映射类的字段    * 也可以用DataConsole.parseSmap(Class,String...)方法获取map    * 这个函数接收两个参数,第一个参数表示映射的类型,第二个开始的参数表示字段名称,函数会在映射类中匹配相应的字段类型    * PS:映射类内部的字段类型不能是基础类型比如int,short,要写成Integer,Short    */   public void find() {    try {     System.out.println(dc.find(       "select top 10 * from test where id>?",       pojo.class,       DataConsole.parseSmap(pojo.class, "id","whichservice"),        10));    } catch (SQLException e) {     e.printStackTrace();    }   }      /**    * 执行更新语句的方法    * 接收1+个参数    * 第一个参数表示SQL更新语句    * 第二个以后的参数表示传入的变量列表,无参数语句不填这些参数    * 返回结果是查询影响的记录条数    */   public void update() {    try {     System.out.println(dc.updatePrepareSQL(       "insert into test(id,text,value) values(?,?,?)",        1,"text","value"));    } catch (SQLException e) {     e.printStackTrace();    }   }      /**    * 执行插入动作,并返回这个操作记录的主键,如果操作无主键或主键不是自增型,返回0    * 参数类似于更新动作,这里演示了没有sql变量的情况    */   public void insertAndReturnKey() {    try {     System.out.println(dc.insertAndReturnKey("insert into test(text,value) values('text','value')"));    } catch (SQLException e) {     e.printStackTrace();    }   }      /**    * 类似于执行select语句,此方法用于执行带有返回结果集的存储过程    */   public void callAndReturnResultSet() {    try {     System.out.println(dc.call(pojo.class,        "{call proc_returnpojo(?)}",        DataConsole.parseSmap(pojo.class, "id","whichservice"),        1));    } catch (Exception e) {     e.printStackTrace();    }   }      /**    * 用于执行存储过程,如果存储过程带有返回值(非output参数),返回接受到的返回值    *  首字段用于处理返回值 所以存储过程写法必须是 {?=call PRODUCENAME(?,?...,?)}    * 比如:    * create proc_testreturn    * begin    * return 1    * end    */   public void callAndReturn() {    try {     System.out.println(dc.callWithReturn("{?=call proc_testreturn}", Types.INTEGER));    } catch (SQLException e) {     e.printStackTrace();    }   }  }
其中用到的pojo类的定义:
package org.sol.util.db;    public class pojo {   private Integer id;   private String text;      public Integer getId() {    return id;   }   public void setId(Integer id) {    this.id = id;   }   public String getText() {    return text;   }   public void setText(String text) {    this.text = text;   }      @Override   public String toString() {    return "pojo [" + (id != null ? "id=" + id + ", " : "")      + (text != null ? "text=" + text : "") + "]";   }     }