手动创建JDBC及连接池封装等
一、适用场景
有些时候在改造别人代码的时候,无法嵌入通用的一些ORM框架,跟现有框架容易冲突,但是又不想使用现有框架的写法,那么这时候就需要手写JDBC。
国庆前小叔在深圳一家500强企业做MES项目开发时候,应该算是三开了,公司首期花了大价钱使用了SAP ME的产品,可惜维护不力加上人员更迭,后面人就不懂了,然后找了一家公司二开,但是二开完,那家公司貌似做不下去了,后面尾款都没收就跑了,然后就有了三开;
系统存在三个独立的分布式的数据库(正式库、中转库(包涵ME的标准表)、历史库),底层连接使用了druid连接池,但是事务管理使用了JTA,底层采用了NamedParameterJdbcTemplate的封装,导致想要改写这些东西,又会影响到二期的功能,所以就另外封装了一套JDBC,并且封装了一些通用的增删改差之类的方法。
二、整体介绍
1、JDBC连接管理工具类:主要为连接的建立、关闭
2、JDBC连接工具类:包含从连接池获取连接、通用的连接方法
3、JDBC连接池工具类:获取框架DruidXADataSource连接池对象
4、结果解析工具类:主要为将查询返回结果转化为想要的对象格式
5、其他:静态文件,获取框架的配置信息(JDBC连接、账号、密码等);枚举类,用于指定对应数据库源(正式库、中转库、测试库);框架的基础配置等
三、代码介绍
1、db.properties
2、db.xml大致如下:
需要引入上面的db.properties
Druid数据源大致配置如下:
3、静态文件,获取以上的xml配置值
Global.Java
import java.io.File;import java.io.IOException;import java.nio.charset.Charset;import java.util.Map;import java.util.concurrent.BlockingQueue;import java.util.concurrent.LinkedBlockingQueue;import org.apache.commons.lang3.StringUtils;import org.springframework.core.io.DefaultResourceLoader;import com.google.common.collect.Maps;public class Global {/*** 当前对象实例*/private static Global global = new Global();/*** 保存全局属性值*/private static Map<String, String> map = Maps.newHashMap();/*** 属性文件加载对象*/private static PropertiesLoader loader = new PropertiesLoader("db.properties");/*** 获取当前对象实例*/public static Global getInstance() {return global;}/*** 获取配置*/public static String getConfig(String key) {String value = map.get(key);if (value == null) {value = loader.getProperty(key);map.put(key, value != null ? value : StringUtils.EMPTY);}return value;}// 数据源及相关参数设置public static final String DB_URL =getConfig("productionJdbc.url");public static final String DB_USERNAME =getConfig("productionJdbc.username");public static final String DB_PASSWORD =getConfig("productionJdbc.password");public static final String DB_DRIVER =getConfig("productionJdbc.driver");public static final String DB_INITIALSIZE =getConfig("ds.initialSize");public static final String DB_MAXACTIVE =getConfig("ds.maxActive");public static final String DB_MINIDLE =getConfig("ds.minIdle");public static final String DB_MAXWAIT =getConfig("ds.maxWait");public static final String DB_TIMEBETWEENEVICTIONRUNSMILLIS =getConfig("ds.timeBetweenEvictionRunsMillis");public static final String DB_MINEVICTABLEIDLETIMEMILLIS =getConfig("ds.minEvictableIdleTimeMillis");public static final String TRANSFERJDBC_DB_URL =getConfig("transferJdbc.url");public static final String TRANSFERJDBC_DB_USERNAME =getConfig("transferJdbc.username");public static final String TRANSFERJDBC_DB_PASSWORD =getConfig("transferJdbc.password");}
DbEnum.java
public enum DbEnum {PROD("1") //生产库,TRANSF("2"); //中转库,HISTORY("3"); //历史库private String value;private DbEnum(String value){this.value = value;}public String getValue() {return value;}@Overridepublic String toString() {return this.value;}}
4、JDBC连接池建立工具
JdbcPoolTool.java
import java.sql.Connection;import java.sql.SQLException;import com.alibaba.druid.pool.xa.DruidXADataSource;import com.byd.mes.base.utils.Global;import com.byd.mes.base.utils.JdbcUtil;import com.byd.mes.base.utils.SpringBeanUtill;import com.byd.mes3.exception.BizException;public class JdbcPoolTool {private static DruidXADataSource dataSourcePro = null;private static DruidXADataSource dataSourceTrans = null;/*** 获取数据库连接* @param dbEnum* @return*/public static Connection getConnection(DbEnum dbEnum){Connection conn = getConectionOfPool(dbEnum);return conn;}/*** 根据不同的数据库从框架中获取Druid连接池* @param dbEnum* @return*/private static Connection getConectionOfPool(DbEnum dbEnum){DruidXADataSource ds = null;Connection poolConn = null;switch(dbEnum.getValue()){case "1":ds = (DruidXADataSource) SpringBeanUtill.getBean("productionJdbcXADataSource");break;case "2":ds = (DruidXADataSource) SpringBeanUtill.getBean("transferJdbcXADataSource");break;default:ds = (DruidXADataSource) SpringBeanUtill.getBean("productionJdbcXADataSource");break;}if(ds.isClosed() || ds == null){ds = setDruidXADataSource(dbEnum);}try {poolConn = ds.getConnection();} catch (SQLException e) {e.printStackTrace();throw new BizException("获取数据库连接出错!");}if(poolConn == null ){// 如果实在不行,手动建立JDBC连接switch(dbEnum.getValue()){case "1":poolConn = JdbcUtil.getConnection(Global.DB_URL,Global.DB_USERNAME,Global.DB_PASSWORD);break;case "2":poolConn = JdbcUtil.getConnection(Global.TRANSFERJDBC_DB_URL,Global.TRANSFERJDBC_DB_USERNAME,Global.TRANSFERJDBC_DB_PASSWORD);break;default:poolConn = JdbcUtil.getConnection(Global.DB_URL,Global.DB_USERNAME,Global.DB_PASSWORD);break;}}return poolConn;}/*** 获取配置文件,并赋值* @param dbEnum* @param poolConn* @return*/private static DruidXADataSource setDruidXADataSource(DbEnum dbEnum) {switch(dbEnum.getValue()){case "1":if(dataSourcePro != null){return dataSourcePro;}dataSourcePro = getDataSourcePro();return dataSourcePro;case "2":if(dataSourceTrans != null){return dataSourceTrans;}dataSourceTrans = getDataSourceTrans();return dataSourceTrans;default:dataSourcePro = getDataSourcePro();return dataSourcePro;}}/*** 获取生产库连接池对象* @return*/private static DruidXADataSource getDataSourcePro() {DruidXADataSource ds = new DruidXADataSource();setCommJdbc(ds);ds.setUrl(Global.DB_URL);ds.setUsername(Global.DB_USERNAME);ds.setPassword(Global.DB_PASSWORD);return ds;}/*** 获取中转库连接池对象* @return*/private static DruidXADataSource getDataSourceTrans() {DruidXADataSource ds = new DruidXADataSource();setCommJdbc(ds);ds.setUrl(Global.TRANSFERJDBC_DB_URL);ds.setUsername(Global.TRANSFERJDBC_DB_USERNAME);ds.setPassword(Global.TRANSFERJDBC_DB_PASSWORD);return ds;}/*** 设置JDBC通用属性(请参考 applicationContext-db.xml 和 application.properties文件的配置)* @param dbEnum* @return*/private static void setCommJdbc(DruidXADataSource ds){//配置初始化大小、最小、最大ds.setInitialSize(Integer.parseInt(Global.DB_INITIALSIZE));ds.setMaxActive(Integer.parseInt(Global.DB_MAXACTIVE));ds.setMinIdle(Integer.parseInt(Global.DB_MINIDLE));//配置获取连接等待超时的时间ds.setMaxWait(Integer.parseInt(Global.DB_MAXWAIT));//配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒ds.setTimeBetweenEvictionRunsMillis(Long.parseLong(Global.DB_TIMEBETWEENEVICTIONRUNSMILLIS));//配置一个连接在池中最小生存的时间,单位是毫秒ds.setMinEvictableIdleTimeMillis(Long.parseLong(Global.DB_MINEVICTABLEIDLETIMEMILLIS));//配置连接驱动ds.setDriverClassName(Global.DB_DRIVER); //设置驱动//连接泄漏监测 超过removeAbandonedTimeout时间后,是否进行没用连接(废弃)的回收ds.setRemoveAbandoned(false);ds.setRemoveAbandonedTimeout(60);//防止过期ds.setValidationQuery("SELECT * FROM DUAL");ds.setTestWhileIdle(true);ds.setTestOnBorrow(false);ds.setTestOnReturn(false);//关闭abanded连接时输出错误日志,将会在回收事件后,在log中打印出回收Connection的错误信息,包括在哪个地方用了Connection却忘记关闭了,方便调试ds.setLogAbandoned(true);//打开PSCache,并且指定每个连接上PSCache的大小ds.setPoolPreparedStatements(true);ds.setMaxPoolPreparedStatementPerConnectionSize(20);}}
5、JdbcUtil工具类(用于关闭连接)
import java.sql.CallableStatement;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;public class JdbcUtil {/**** 释放资源方法*/public static void close(PreparedStatement ps , Connection conn){if (ps != null){try {ps.close();} catch (SQLException e) {e.printStackTrace();}}if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}}}/**** 释放资源方法*/public static void close(CallableStatement ps , Connection conn){if (ps != null){try {ps.close();} catch (SQLException e) {e.printStackTrace();}}if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}}}/*** 释放资源方法*/public static void close(ResultSet rs, Statement stmt, Connection conn) {if (rs != null) {try {rs.close();} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}}if (stmt != null) {try {stmt.close();} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}}if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}}}/*** 释放资源方法*/public static void close(ResultSet rs, CallableStatement stmt, Connection conn) {if (rs != null) {try {rs.close();} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}}if (stmt != null) {try {stmt.close();} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}}if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}}}/*** 释放资源方法*/public static void close(Statement stmt, Connection conn) {if (stmt != null) {try {stmt.close();} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}}if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}}}}
6、数据库连接使用工具(后台增删改查通过这个工具类)
JdbcTool.JAVA
import java.math.BigDecimal;import java.sql.Array;import java.sql.Blob;import java.sql.CallableStatement;import java.sql.Clob;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Types;import java.util.ArrayList;import java.util.Date;import java.util.HashMap;import java.util.List;import java.util.Map;public class JdbcTool {public static Connection getConnectionByDb(Connection conn ,DbEnum dbEnum){switch(dbEnum.getValue()){case "1":conn = JdbcPoolTool.getConnection(DbEnum.PROD);break;case "2":conn = JdbcPoolTool.getConnection(DbEnum.TRANSF);break;default:conn = JdbcPoolTool.getConnection(DbEnum.PROD);break;}return conn;}public static List<Map<String,Object>> queryForMap(DbEnum dbEnum,String sql){Connection conn = null;PreparedStatement psmt = null;ResultSet rs = null;List<Map<String,Object>> list = new ArrayList<Map<String,Object>>();try {conn = getConnectionByDb(conn,dbEnum);psmt = conn.prepareStatement(sql);rs = psmt.executeQuery();list = ResultSetTool.resultSetToListMap(rs);} catch (Exception e) {JdbcUtil.close(rs, psmt, conn);throw new BizException(e.getMessage());}finally{JdbcUtil.close(rs, psmt, conn);}return list;}public static Map<String,Object> queryForMapSingle(DbEnum dbEnum,String sql){List<Map<String,Object>> list = queryForMap(dbEnum,sql);Map<String,Object> map = new HashMap<String,Object>();if(list != null && list.size() >0){map = list.get(0);}return map;}public static List<Map<String,Object>> queryForMap(DbEnum dbEnum,String sql,List<Object> paramsList){Connection conn = null;PreparedStatement psmt = null;ResultSet rs = null;List<Map<String,Object>> list = new ArrayList<Map<String,Object>>();if(paramsList != null && paramsList.size() >0){if(countInterrogation(sql) != paramsList.size()){throw new BizException("传入的参数个数不符合!执行语句"+sql+"传入的参数个数为"+paramsList.size());}}try {conn = getConnectionByDb(conn,dbEnum);psmt = conn.prepareStatement(sql);psmt = ResultSetTool.listObjectSetToPs(paramsList, psmt);rs = psmt.executeQuery();list = ResultSetTool.resultSetToListMap(rs);} catch (Exception e) {JdbcUtil.close(rs, psmt, conn);throw new BizException(e.getMessage());}finally{JdbcUtil.close(rs, psmt, conn);}return list;}public static Map<String,Object> queryForMapSingle(DbEnum dbEnum,String sql,List<Object> paramsList){List<Map<String,Object>> list = queryForMap(dbEnum,sql,paramsList);Map<String,Object> map = new HashMap<String,Object>();if(list != null && list.size() >0){map = list.get(0);}return map;}public static <T> List<T> queryForList(DbEnum dbEnum,String sql,Class<T> clazz){Connection conn = null;PreparedStatement psmt = null;ResultSet rs = null;List<T> list = new ArrayList<>();try {conn = getConnectionByDb(conn,dbEnum);psmt = conn.prepareStatement(sql);rs = psmt.executeQuery();list =ResultSetTool.resultSetToListBean(rs, clazz);} catch (Exception e) {JdbcUtil.close(rs, psmt, conn);throw new BizException(e.getMessage());}finally{JdbcUtil.close(rs, psmt, conn);}return list;}public static <T> T queryForBean(DbEnum dbEnum,String sql,Class<T> clazz){List<T> list = queryForList(dbEnum,sql, clazz);if(list != null && list.size() >0){return list.get(0);}return null;}public static <T> List<T> queryForList(DbEnum dbEnum,String sql,List<Object> paramsList,Class<T> clazz){Connection conn = null;PreparedStatement psmt = null;ResultSet rs = null;List<T> list = new ArrayList<>();if(paramsList != null && paramsList.size() >0){if(countInterrogation(sql) != paramsList.size()){throw new BizException("传入的参数个数不符合!执行语句"+sql+"传入的参数个数为"+paramsList.size());}}try {conn = getConnectionByDb(conn,dbEnum);psmt = conn.prepareStatement(sql);psmt = ResultSetTool.listObjectSetToPs(paramsList, psmt);rs = psmt.executeQuery();list =ResultSetTool.resultSetToListBean(rs, clazz);} catch (Exception e) {JdbcUtil.close(rs, psmt, conn);throw new BizException(e.getMessage());}finally{JdbcUtil.close(rs, psmt, conn);}return list;}/*** 更新**/public static void update(DbEnum dbEnum,String sql){Connection conn = null;PreparedStatement psmt = null;ResultSet rs = null;try {conn = getConnectionByDb(conn,dbEnum);//设置事务属性conn.setAutoCommit(false);psmt = conn.prepareStatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);psmt.executeUpdate();//提交,设置事务初始值conn.commit();conn.setAutoCommit(true);} catch (Exception e) {try{//提交失败,执行回滚操作conn.rollback();}catch (SQLException sqlE) {sqlE.printStackTrace();throw new BizException("执行出错,错误原因:"+e.getMessage()+",回滚执行失败!!!");}JdbcUtil.close(rs, psmt, conn);throw new BizException(e.getMessage());}finally{JdbcUtil.close(rs, psmt, conn);}}public static void update(DbEnum dbEnum,String sql,List<Object> paramsList){Connection conn = null;PreparedStatement psmt = null;ResultSet rs = null;try {conn = getConnectionByDb(conn,dbEnum);//设置事务属性conn.setAutoCommit(false);psmt = conn.prepareStatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);psmt = ResultSetTool.listObjectSetToPs(paramsList, psmt);psmt.executeUpdate();//提交,设置事务初始值conn.commit();conn.setAutoCommit(true);} catch (Exception e) {try{//提交失败,执行回滚操作conn.rollback();}catch (SQLException sqlE) {sqlE.printStackTrace();throw new BizException("执行出错,错误原因:"+e.getMessage()+",回滚执行失败!!!");}JdbcUtil.close(rs, psmt, conn);throw new BizException(e.getMessage());}finally{JdbcUtil.close(rs, psmt, conn);}}public static void batchUpdate(DbEnum dbEnum,String sql,List<List<Object>> paramsList){Connection conn = null;PreparedStatement psmt = null;ResultSet rs = null;//sql包含问号个数int count = countInterrogation(sql);for(List<Object> list:paramsList){if(list.size() != count){throw new BizException("传入的参数个数不符合!执行语句"+sql+"传入的参数个数为"+ list.size());}}try {conn = getConnectionByDb(conn,dbEnum);//设置事务属性conn.setAutoCommit(false);psmt = conn.prepareStatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);for(int i=0; i<paramsList.size(); i++){psmt = ResultSetTool.listObjectSetToPs(paramsList.get(i), psmt);psmt.addBatch();}psmt.executeBatch();//提交,设置事务初始值conn.commit();conn.setAutoCommit(true);} catch (Exception e) {try{//提交失败,执行回滚操作conn.rollback();}catch (SQLException sqlE) {sqlE.printStackTrace();throw new BizException("执行出错,错误原因:"+e.getMessage()+",回滚执行失败!!!");}JdbcUtil.close(rs, psmt, conn);throw new BizException(e.getMessage());}finally{JdbcUtil.close(rs, psmt, conn);}}/*** 调用无参无返回值存储过程* @param dbEnum* @param procedureName*/public static void callProcedureNon(DbEnum dbEnum,String procedureName){Connection conn = null;CallableStatement cstmt = null;try {conn = getConnectionByDb(conn,dbEnum);StringBuilder strSb = new StringBuilder();strSb.append(" {call ");strSb.append(procedureName);strSb.append("()}");cstmt = conn.prepareCall(strSb.toString());cstmt.execute();} catch (Exception e) {throw new BizException(e.getMessage());}finally{JdbcUtil.close(cstmt, conn);}}/*** 调用无参有返回值的存储过程* @param dbEnum* @param procedureName* @return*/public static List<Object> callProcedure(DbEnum dbEnum,String procedureName){Connection conn = null;CallableStatement cstmt = null;ResultSet rs = null;List<Object> list = new ArrayList<Object>();try {conn = getConnectionByDb(conn,dbEnum);StringBuilder strSb = new StringBuilder();strSb.append(" {call ");strSb.append(procedureName);strSb.append("()}");cstmt = conn.prepareCall(strSb.toString());rs = cstmt.executeQuery();while(rs.next()){int rowNum = rs.getRow();for(int i=0;i<rowNum;i++){list.add(rs.getObject(i));}}} catch (Exception e) {throw new BizException(e.getMessage());}finally{JdbcUtil.close(rs, cstmt, conn);}return list;}/*** 调用有参无返回值的存储过程* @param dbEnum* @param procedureName* @param ins*/public static void callProcedure(DbEnum dbEnum,String procedureName,List<Object> ins){Connection conn = null;CallableStatement cstmt = null;try {conn = getConnectionByDb(conn,dbEnum);StringBuilder strSb = new StringBuilder();strSb.append(" {call ");strSb.append(procedureName);strSb.append("(");if(ins != null && ins.size() > 0){for(int i=0;i<ins.size(); i++){strSb.append("?,");}strSb.setLength(strSb.length()-1);}strSb.append(")}");cstmt = conn.prepareCall(strSb.toString());cstmt = listOject2CallableStatement(cstmt,ins);cstmt.execute();} catch (Exception e) {throw new BizException(e.getMessage());}finally{JdbcUtil.close(cstmt, conn);}}/*** 调用有出入参的存储过程* @param dbEnum* @param procedureName* @param ins*/public static List<Object> callProcedure(DbEnum dbEnum,String procedureName,List<Object> ins,List<ProcedureOutParameter> outs){Connection conn = null;CallableStatement cstmt = null;List<Object> result = new ArrayList<Object>();try {conn = getConnectionByDb(conn,dbEnum);StringBuilder strSb = new StringBuilder();strSb.append(" {call ");strSb.append(procedureName);strSb.append("(");if(ins != null && ins.size() > 0){for(int i=0; i<ins.size(); i++){strSb.append("?,");}if(outs != null && outs.size() >0){for(int j=0; j<outs.size(); j++){strSb.append("?,");}}strSb.setLength(strSb.length()-1);}strSb.append(")}");cstmt = conn.prepareCall(strSb.toString());cstmt = listOject2CallableStatement(cstmt,ins);if(outs != null && outs.size() >0){for(int j=0; j<outs.size(); j++){cstmt.registerOutParameter(outs.get(j).getLeft(), outs.get(j).getRight());}}cstmt.execute();if(outs != null && outs.size() >0){for(int j=0; j<outs.size(); j++){int type = outs.get(j).getRight();int left = outs.get(j).getLeft();switch(type){case Types.CHAR:result.add(cstmt.getString(left));break;case Types.DATE:result.add(cstmt.getDate(left));break;case Types.INTEGER:result.add(cstmt.getBigDecimal(left));break;case Types.FLOAT:result.add(cstmt.getBigDecimal(left));break;case Types.DOUBLE:result.add(cstmt.getBigDecimal(left));break;case Types.BOOLEAN:result.add(cstmt.getBoolean(left));break;case Types.BLOB:result.add(cstmt.getBlob(left));break;case Types.CLOB:result.add(cstmt.getClob(left));break;case Types.NVARCHAR:result.add(cstmt.getString(left));break;case Types.VARCHAR:result.add(cstmt.getString(left));break;case Types.TIME:result.add(cstmt.getTime(left));break;case Types.TIMESTAMP:result.add(cstmt.getTimestamp(left));break;default:result.add(cstmt.getObject(left));break;}}}} catch (Exception e) {throw new BizException(e.getMessage());}finally{JdbcUtil.close(cstmt, conn);}return result;}public static CallableStatement listOject2CallableStatement(CallableStatement cstmt,List<Object> params){if(cstmt != null && params != null && params.size() >0){try{for(int i=0; i<params.size(); i++){Object p = params.get(i);if(p instanceof Integer){cstmt.setInt(i+1, (Integer)p);}else if(p instanceof String){cstmt.setString(i+1, (String)p);}else if(p instanceof Boolean){cstmt.setBoolean(i+1, (Boolean)p);}else if(p instanceof Date){// psmt.setDate(i+1, getDate((Date)p));cstmt.setTimestamp(i+1, ResultSetTool.getTimestamp((Date)p));}else if(p instanceof Double){cstmt.setDouble(i+1, (Double)p);}else if(p instanceof Float){cstmt.setFloat(i+1, (Float)p);}else if(p instanceof Long){cstmt.setLong(i+1, (Long)p);}else if(p instanceof Blob){cstmt.setBlob(i+1, (Blob)p);}else if(p instanceof Array){cstmt.setArray(i+1, (Array)p);}else if(p instanceof BigDecimal){cstmt.setBigDecimal(i+1, (BigDecimal)p);}else if(p instanceof Byte){cstmt.setByte(i+1, (Byte)p);}else if(p instanceof Clob){cstmt.setClob(i+1, (Clob)p);}else{cstmt.setString(i+1, (String)p);}}}catch(Exception e){throw new BizException("调用存储过程入参转换错误:"+e.getMessage());}}return cstmt;}/*** 计算字符串包含的问号数量* @param str* @return*/private static int countInterrogation(String str){int count = 0;for(int i=0;i<str.length();i++){if(str.charAt(i) == '?'){count++;}}return count;}}
7、JDBC的ResultSet工具类
ResultSetTool.java
import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.math.BigDecimal;import java.sql.Array;import java.sql.Blob;import java.sql.Clob;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.ResultSetMetaData;import java.sql.SQLException;import java.sql.Timestamp;import java.util.ArrayList;import java.util.Date;import java.util.HashMap;import java.util.List;import java.util.Map;import net.sf.json.JSONArray;import net.sf.json.JSONException;import net.sf.json.JSONObject;/*** JDBC的ResultSet工具类* @author jianbin.lei* @date 2019-09-03*/public class ResultSetTool {/*** 转换数据 JDBC结果集转实体** @param resultSet 结果集* @param clazz 实体字节码文件对象* @param <T> 实体类型* @throws Exception sql异常 NoClass异常等等*/public static <T> List<T> resultSetToListBean(ResultSet resultSet, Class<T> clazz) throws Exception {//获取全部类方法 包括父类的Method[] declaredMethods = clazz.getMethods();List<T> list = new ArrayList<>();ResultSetMetaData metaData = resultSet.getMetaData();while (resultSet.next()) {//反射实例化对象T obj = clazz.newInstance();//遍历类调用方法for (Method method : declaredMethods) {//获取方法名String name = method.getName();if (!name.startsWith("set")){//只要settercontinue;}//获取数据库名 驼峰命名法转数据库字段命名法String dbName = getDbName(name);//遍历数据库所有列for (int i = 1; i <= metaData.getColumnCount(); i++) {//抓取指定列赋值if (metaData.getColumnName(i).equalsIgnoreCase(dbName)) {if (resultSet.getObject(i) != null) {//赋值setValue(obj,method,resultSet,i);}break;}}}list.add(obj);}return list;}/*** 将resultSet转换为List<Map<String,Object>>* @param rs* @return* @throws Exception*/public static List<Map<String,Object>> resultSetToListMap(ResultSet rs) throws Exception {//获取全部类方法 包括父类的List<Map<String,Object>> list = new ArrayList<Map<String,Object>>();ResultSetMetaData metaData = rs.getMetaData();int columnCount = metaData.getColumnCount();// 遍历ResultSet中的每条数据while (rs.next()) {Map<String,Object> map = new HashMap<String,Object>();// 遍历每一列for (int i = 1; i <= columnCount; i++) {String columnName =metaData.getColumnLabel(i);String value = rs.getString(columnName);map.put(columnName, value);}list.add(map);}return list;}/*** 将resultSet转化为JSON数组* @param rs* @return* @throws SQLException* @throws JSONException*/public static JSONArray resultSetToJsonArry(ResultSet rs) throws SQLException,JSONException {// json数组JSONArray array = new JSONArray();// 获取列数ResultSetMetaData metaData = rs.getMetaData();int columnCount = metaData.getColumnCount();// 遍历ResultSet中的每条数据while (rs.next()) {JSONObject jsonObj = new JSONObject();// 遍历每一列for (int i = 1; i <= columnCount; i++) {String columnName =metaData.getColumnLabel(i);String value = rs.getString(columnName);jsonObj.put(columnName, value);}array.add(jsonObj);}return array;}/*** 将resultSet转化为JSONObject* @param rs* @return* @throws SQLException* @throws JSONException*/public static JSONObject resultSetToJsonObject(ResultSet rs) throws SQLException,JSONException {// json对象JSONObject jsonObj = new JSONObject();// 获取列数ResultSetMetaData metaData = rs.getMetaData();int columnCount = metaData.getColumnCount();// 遍历ResultSet中的每条数据if (rs.next()) {// 遍历每一列for (int i = 1; i <= columnCount; i++) {String columnName = metaData.getColumnLabel(i);String value = rs.getString(columnName);jsonObj.put(columnName, value);}}return jsonObj;}/*** 将list参数设置到PreparedStatement中* @param list* @param psmt* @return* @throws SQLException*/public static PreparedStatement listObjectSetToPs(List<Object> params,PreparedStatement psmt) throws SQLException{if(params != null && params.size() >0){for(int i=0;i<params.size();i++){Object p = params.get(i);if(p instanceof Integer){psmt.setInt(i+1, (Integer)p);}else if(p instanceof String){psmt.setString(i+1, (String)p);}else if(p instanceof Boolean){psmt.setBoolean(i+1, (Boolean)p);}else if(p instanceof Date){// psmt.setDate(i+1, getDate((Date)p));psmt.setTimestamp(i+1, getTimestamp((Date)p));}else if(p instanceof Double){psmt.setDouble(i+1, (Double)p);}else if(p instanceof Float){psmt.setFloat(i+1, (Float)p);}else if(p instanceof Long){psmt.setLong(i+1, (Long)p);}else if(p instanceof Blob){psmt.setBlob(i+1, (Blob)p);}else if(p instanceof Array){psmt.setArray(i+1, (Array)p);}else if(p instanceof BigDecimal){psmt.setBigDecimal(i+1, (BigDecimal)p);}else if(p instanceof Byte){psmt.setByte(i+1, (Byte)p);}else if(p instanceof Clob){psmt.setClob(i+1, (Clob)p);}else{psmt.setString(i+1, (String)p);}}}return psmt;}public static Timestamp getTimestamp(Date date){return new Timestamp(date.getTime());}public static java.sql.Date getDate(long time){return new java.sql.Date(time);}public static java.sql.Date getDate(Date date){return new java.sql.Date(date.getTime());}/*** 赋值操作,* 主要是处理数据类型* 此处只简单处理下基本数据类型和Date类型* @param obj 泛型对象* @param method 方法* @param resultSet 结果集* @param i 脚标* @param <T> 泛型*/private static <T> void setValue(T obj, Method method, ResultSet resultSet, int i) throws SQLException, InvocationTargetException, IllegalAccessException {//Setter方法只有一个参数,获取参数类型名称String name = method.getParameterTypes()[0].getName().toLowerCase();if (name.contains("string")){method.invoke(obj, resultSet.getString(i));}else if (name.contains("short")){method.invoke(obj,resultSet.getShort(i));}else if (name.contains("int") || name.contains("integer")){method.invoke(obj,resultSet.getInt(i));}else if (name.contains("bigdecimal")){method.invoke(obj,resultSet.getBigDecimal(i));}else if(name.contains("long")){method.invoke(obj,resultSet.getLong(i));}else if (name.contains("float")){method.invoke(obj,resultSet.getFloat(i));}else if (name.contains("double")){method.invoke(obj,resultSet.getDouble(i));}else if (name.contains("boolean")){method.invoke(obj,resultSet.getBoolean(i));}else if (name.contains("date")){method.invoke(obj,resultSet.getDate(i));}else {method.invoke(obj, resultSet.getObject(i));}}/*** 实体setter名称转对应数据库列的列名* 需要遵守命名规范,java(驼峰命名法),数据库(全小写,单词间用'_'隔开)* @param name setter名称* @return 数据库列名*/private static String getDbName(String name) {//根据setter命名规则获取对应的属性名name = name.substring(3,4).toLowerCase()+name.substring(4);//获取数据库对应列名StringBuffer buffer = new StringBuffer();char[] nameChars = name.toCharArray();for (char nameChar : nameChars) {if (nameChar >= 'A' && nameChar <= 'Z') {//将大写字母转换为下划线和对应的小写字母组合buffer.append("_").append(String.valueOf(nameChar).toLowerCase());} else {buffer.append(String.valueOf(nameChar));}}return buffer.toString();}}
四、使用
1、更新
StringBuilder sql = new StringBuilder();sql.append(" UPDATE MES3_BASKET SET BASKET_NO =?,BASKET_NAME=?");sql.append(" ,BASKET_DESC =?,BASKET_QTY=?,MODIFY_USER=? ");sql.append(" ,MODIFY_DATE=sysdate,BASKET_KZLS=?,BASKET_TYPE=?");sql.append(" WHERE PID= ?");List<Object> paramsList = new ArrayList<>();paramsList.add(map.get("BASKET_NO"));paramsList.add(map.get("BASKET_NAME"));paramsList.add(map.get("BASKET_DESC"));paramsList.add(map.get("BASKET_QTY"));paramsList.add(map.get("MODIFY_USER"));paramsList.add(map.get("BASKET_KZLS"));paramsList.add(map.get("BASKET_TYPE"));paramsList.add(map.get("PID"));JdbcTool.update(DbEnum.PROD, sql.toString(), paramsList);
2、查询返回单条数据的Map
String sfc = "1000020001";StringBuilder sqlSb = new StringBuilder();sqlSb.append(" SELECT DATA03 FROM Z_FORMES_SFC WHERE SFC ='").append(sfc).append("'");Map<String,Object> sfcMap = JdbcTool.queryForMapSingle(DbEnum.PROD, sqlSb.toString());
3、查询返回实体类对象
StringBuilder sqlSb = new StringBuilder();sqlSb.append("SELECT * FROM STUDENT WHERE NAME='张三'");return JdbcTool.queryForBean(DbEnum.PROD, sqlSb.toString(), Student.class);
StringBuilder sql = new StringBuilder("");sql.append(" select PID, SEQ, NAME, OPERATION_ID, RESOURCE_ID, STATUS, STEP_MAIN_ID, SIMPLE");sql.append(" from STEP_DETAIL ");sql.append(" where RESOURCE_ID = ? and OPERATION_ID = ? order by SEQ ");List<Object> paramsList = new ArrayList<>();paramsList.add("123123");paramsList.add("2222");List<StepDetail> param =JdbcTool.queryForList(DbEnum.PROD, sql.toString(), paramsList,StepDetail.class);
4、查询返回List Map
StringBuilder sqlSb = new StringBuilder();sqlSb.append("SELECT * FROM STUDENT");List<Map<String,Object>> cellList = JdbcTool.queryForMap(DbEnum.PROD, sqlSb.toString());
StringBuilder sql = new StringBuilder();sql.append("SELECT a.RESRCE AS resourceNo,b.OPERATION AS opeationNo,a.HANDLE AS R_HANDLE,b.HANDLE AS O_HANDLE");sql.append(" FROM RESRCE a");sql.append(" INNER JOIN OPERATION b ON SUBSTR (a.OPERATION_BO, 0,INSTR (a.OPERATION_BO, ',', -2, 1)-1) = SUBSTR (b.HANDLE, 0,INSTR (b.HANDLE, ',', -2, 1)-1) ");sql.append(" WHERE 1=1 ");sql.append(" AND a.RESRCE = ? ");//问号为占位符sql.append(" AND a.OPERATION_BO IS NOT NULL ");sql.append(" ORDER BY RESRCE ");List<Object> paramsList = new ArrayList<>();paramsList.add(resourceNo);//根据顺序,查询时候替换占位符List<Map<String, Object>> param =JdbcTool.queryForMap(DbEnum.TRANSF, sql.toString(), paramsList);
5、批量更新
List<List<Object>> paramsList = new ArrayList<>();List<Object> params = new ArrayList<>();params.add("112312");params.add(112312);params.add("3213212");paramsList.add(params);String sql = " DELETE FROM STEP_MAIN WHERE PID=? AND MM=? AND CC=?";JdbcTool.batchUpdate(DbEnum.PROD, sql, paramsList);
6、存储过程调用
List<Object> ins = new ArrayList<>();ins.add(mResource.get("OPEATIONNO"));ins.add(map.get("SCAN_VALUE"));List<ProcedureOutParameter> outs = new ArrayList<>();ProcedureOutParameter p = new ProcedureOutParameter();p.setLeft(3);p.setRight(1);outs.add(p);List<Object> list = JdbcTool.callProcedure(DbEnum.PROD, "P_POD_GETFZREWORK", ins, outs);
