一、业务阐述
在开发中查询的数据库结果集,既要连接数据库、执行数据库操作、关闭数据库,还要把结果集的记录人为的设置到自己封装的DAO中等一系列的重复代码。
本文主要是想解决:用户只需要得到数据库连接,写sql语句,自己封装dao,其余的操作由封转的小框架解决这些重复的工作,用户得到的只是一个集合List。
List里面的元素有集合Map其中key是数据库中的字段类型,value是字段类型对应的值这个函数
DBUtil.executeQuery(con, sql)
List还提供集合元素存放的是dao对象,一条数据库记录对应一个dao对象,此函数是
DBUtil.executeQuery(con, sql,Vehicle.class)
以下提供源码的叙述
二、源码解说
测试类
- package com.hewen.dao.manage;
- import java.sql.Connection;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import java.util.List;
- public class Main
- {
- public static void main(String[] args)
- {
- Connection con;
- try {
- con = DBTest.getCon();
- } catch (SQLException e) {
- e.printStackTrace();
- return;
- }
- PreparedStatement pst = null;
- ResultSet rs = null;
- String sql = "select * from t_vehicle t where t.vehicle_id<4";
- /**
- * 该方法用到的技术是通过结果集的列属性的性质得到,没有用到反射机制
- * 这个测试用例也是把查询的结果集放到List集合
- * 里面的元素是集合Map,key是数据库中的字段类型,value是
- * 字段类型对应的值,
- * 查询的结果如:[{KIND_ID=1, DEF_FLAG=null, CHANNELNO=1, SN=陆震,(822)22911,13771000789,
- * BUYDATE=2010-02-26, DELETETIME=null, STAMP=2010-02-26, REGDATE=null, ISDELETED=0,
- * VEHICLE_ID=2, NUMBER_PLATE=苏B10001, VEHICLESTATE=待命状态(对应现场返回), USEDATE=2010-02-26,
- * INTERPHONENO=null, NUMBER_PLATE_TYPE_ID=4, TEL2=null, STYLE=null, COLOR=null,
- * INTERPHONEID=null, LASTMAINTAINTIME=null, INITDISTANCE=0, LAST_UPDATE_TIME=2010-02-26,
- * REMARK=null, TEL=null, SUPERVISER=null},
- * {KIND_ID=3, DEF_FLAG=null, CHANNELNO=1, SN=陆震,
- * (822)22911,13771000789, BUYDATE=2010-02-26, DELETETIME=null, STAMP=2010-02-26,
- * REGDATE=null, ISDELETED=0, VEHICLE_ID=3, NUMBER_PLATE=苏B90003,
- * VEHICLESTATE=待命状态(对应现场返回), USEDATE=2010-02-26, INTERPHONENO=null,
- * NUMBER_PLATE_TYPE_ID=4, TEL2=13151000793, STYLE=面包车, COLOR=白, INTERPHONEID=null,
- * LASTMAINTAINTIME=null, INITDISTANCE=0, LAST_UPDATE_TIME=2010-02-26, REMARK=null,
- * TEL=22916, SUPERVISER=杨兴华}]
- */
- try {
- List list=DBUtil.executeQuery(con, sql);
- System.out.println(list);
- } catch (SQLException e) {
- e.printStackTrace();
- }
- /**
- * 这个测试用例只是把查询的结果集中的某一条记录映射到了dao对象中,
- * 查询的结果如:
- * vehicle:vehicle_id: 2 numberPlate: 苏B10001 deleteDate: null
- vehicle:vehicle_id: 3 numberPlate: 苏B90003 deleteDate: null
- */
- /* try {
- pst = con.prepareStatement(sql);
- rs = pst.executeQuery();
- while(rs.next()){
- Vehicle r = (Vehicle) DBUtil.getFirstObjectFromRs(rs, Vehicle.class);
- System.out.println("vehicle:" + r);
- }
- } catch (SQLException e) {
- e.printStackTrace();
- }finally{
- DBUtil.closeRs(rs);
- DBUtil.closePst(pst);
- DBUtil.closeCon(con);
- }*/
- /**
- * 方法是用的反射机制
- * 这个测试用例是测试executeQuery函数,把查询的结果集放到List集合
- * 并且集合元素存放的是dao对象,一条数据库记录对应一个dao对象,
- * 打印出来的结果如:
- * [vehicle_id: 2 numberPlate: 苏B10001 deleteDate: null,
- * vehicle_id: 3 numberPlate: 苏B90003 deleteDate: null]
- *
- */
- /* try {
- List list=DBUtil.executeQuery(con, sql,Vehicle.class);
- System.out.println(list);
- } catch (SQLException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }*/
- }
- }
封装dao DBUtil类
- package com.hewen.dao.manage;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- import java.lang.reflect.Type;
- import java.sql.Connection;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
- import java.sql.ResultSetMetaData;
- import java.sql.SQLException;
- import java.sql.Statement;
- import java.sql.Types;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- /***
- * 注意利用查询出数据库的一条记录映射到相应的dao中,写相应的dao一定要注意字段,一定
- * 要与数据库的记录字段相对应,大小写可以忽略,但是字段不一致就返回错误的数据
- *
- * private static Object getValueFromRs(ResultSet rs, String fieldName, Type t) throws SQLException
- * 此接口有个小的问题就是如果,获取的字段值是空值或者为null,而你自己的需求就是想要获取的字段为一个
- * 默认的值,那就只需要客户该写这个方法,进行判断就可以
- * @author Administrator
- *
- */
- public class DBUtil {
- /**
- * 对操作的数据库回滚
- * @param con 对数据库操作所得到的链接
- */
- public static void rollBack(Connection con){
- try {
- con.rollback();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- /***
- *
- * @param con 数据库jdbc链接
- * @param sql 执行的sql语句
- * @return 返回查询的记录数,记录存储在集合List里面,
- * 里面的元素是集合Map,key是数据库中的字段类型,value是
- * 字段类型对应的值
- * @throws SQLException
- */
- public static List<Map<String, Object>> executeQuery(Connection con, String sql) throws SQLException{
- PreparedStatement pst = null;
- ResultSet rs = null;
- try {
- pst = con.prepareStatement(sql);
- rs = pst.executeQuery();
- return getListFromRsLowerCase(rs);
- }finally{
- closeRs(rs);
- closePst(pst);
- }
- }
- /***
- * 执行sql语句,把结果集存放到List集合里,集合的元素是dao对象
- * @param con 数据库得到的链接
- * @param sql 执行查询的sql语句
- * @param c 把一条条记录要映射的dao类中的对象中去
- * @return
- * @throws SQLException
- */
- public static List<Object> executeQuery(Connection con, String sql, Class<?> c) throws SQLException{
- PreparedStatement pst = null;
- ResultSet rs = null;
- try {
- pst = con.prepareStatement(sql);
- rs = pst.executeQuery();
- return getListFromRs(rs, c);
- }finally{
- closeRs(rs);
- closePst(pst);
- }
- }
- /**
- * 得到结果集存储到list中
- * @param rs 查询的结果集
- * @return
- * @throws SQLException
- */
- public static List<Map<String, Object>> getListFromRs(ResultSet rs) throws SQLException{
- ResultSetMetaData md = rs.getMetaData();//得到结果集列的属性
- int columns = md.getColumnCount();//得到记录有多少列
- int i;
- List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
- while(rs.next()){
- Map<String, Object> map = new HashMap<String, Object>();
- for(i = 0; i < columns; i++){
- map.put(md.getColumnName(i + 1), getValueByType(rs, md.getColumnType(i + 1), md.getColumnName(i + 1)));
- }
- list.add(map);
- }
- return list;
- }
- /**
- * 这个与getListFromRs(ResultSet rs)差不多,只是把数据库的字段变成小写
- *
- * @param rs
- * @return
- * @throws SQLException
- */
- public static List<Map<String, Object>> getListFromRsLowerCase(ResultSet rs) throws SQLException{
- ResultSetMetaData md = rs.getMetaData();
- int columns = md.getColumnCount();
- int i;
- List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
- while(rs.next()){
- Map<String, Object> map = new HashMap<String, Object>();
- for(i = 0; i < columns; i++){
- map.put(md.getColumnName(i + 1).toLowerCase(), getValueByType(rs, md.getColumnType(i + 1), md.getColumnName(i + 1)));
- }
- list.add(map);
- }
- return list;
- }
- /**
- * 这个与getListFromRs(ResultSet rs)功能一样,只是把数据库的字段变成大写
- * @param rs
- * @return
- * @throws SQLException
- */
- public static List<Map<String, Object>> getListFromRsUpperCase(ResultSet rs) throws SQLException{
- ResultSetMetaData md = rs.getMetaData();
- int columns = md.getColumnCount();
- int i;
- List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
- while(rs.next()){
- Map<String, Object> map = new HashMap<String, Object>();
- for(i = 0; i < columns; i++){
- map.put(md.getColumnName(i + 1).toUpperCase(), getValueByType(rs, md.getColumnType(i + 1), md.getColumnName(i + 1)));
- }
- list.add(map);
- }
- return list;
- }
- /***
- *
- * @param rs 查询的结果集
- * @param c 集合元素存放的dao对象
- * @return
- * @throws SQLException
- */
- public static List<Object> getListFromRs(ResultSet rs, Class<?> c) throws SQLException{
- List<Object> list = new ArrayList<Object>();
- try {
- while(rs.next()){
- Object o = initObjectFromRsIfExist(rs, c);
- list.add(o);
- }
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InstantiationException e) {
- e.printStackTrace();
- }
- return list;
- }
- /**
- *
- * @param rs 查询的结果集
- * @param c 结果集一条记录,而一条记录所对应的dao类
- * @return
- * @throws SQLException
- */
- public static Object getFirstObjectFromRs(ResultSet rs, Class<?> c) throws SQLException{
- Object o = null;
- try {
- o = initObjectFromRsIfExist(rs, c);
- } catch (InstantiationException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- }
- return o;
- }
- /***
- *
- * @param rs 查询出来的结果集
- * @param type SQL type from java.sql.Types
- * @param name 数据库记录所对应的字段名称
- * @return 返回一条记录的一个列值
- * @throws SQLException
- */
- private static Object getValueByType(ResultSet rs, int type, String name) throws SQLException{
- switch(type){
- case Types.NUMERIC:
- return rs.getLong(name);
- case Types.VARCHAR:
- //if(rs.getString(name)==null){
- //return "";
- //}
- return rs.getString(name);
- case Types.DATE:
- //if(rs.getDate(name)==null){
- //return System.currentTimeMillis();
- // }
- return rs.getDate(name);
- case Types.TIMESTAMP:
- return rs.getTimestamp(name).toString().substring(0,rs.getTimestamp(name).toString().length()-2);
- case Types.INTEGER:
- return rs.getInt(name);
- case Types.DOUBLE:
- return rs.getDouble(name);
- case Types.FLOAT:
- return rs.getFloat(name);
- case Types.BIGINT:
- return rs.getLong(name);
- default:
- return rs.getObject(name);
- }
- }
- /***
- * 查询dao映射的字段是否在记录在数据库包含的字段
- * @param rs 查询的记录集
- * @param fieldName dao映射的字段
- * @return 如果包含在数据库记录集里面,返回true,否则false
- * @throws SQLException
- */
- private static boolean rsContainsFields(ResultSet rs, String fieldName) throws SQLException{
- ResultSetMetaData md = rs.getMetaData();
- for(int i = 0; i < md.getColumnCount(); i++){
- if(md.getColumnName(i + 1).equalsIgnoreCase(fieldName)){
- return true;
- }
- }
- return false;
- }
- /***
- * 这个函数与initObjectFromRsIfExist函数实现的功能是一样,只是
- * 没有判断dao中的字段是否与数据库记录所定义的字段是一样的,
- * 没有判断时如果自己设置的dao字段与数据库的字段不一致就会报异常
- * @param rs
- * @param c
- * @return
- * @throws InstantiationException
- * @throws SQLException
- * @throws IllegalAccessException
- */
- private static Object initObjectFromRs(ResultSet rs, Class<?> c) throws InstantiationException, SQLException, IllegalAccessException{
- Object o = c.newInstance();
- Method[] methods = o.getClass().getMethods();
- for(Method m: methods){
- if(m.getName().startsWith("set")){
- try {
- m.invoke(o, getParamValueFromRs(rs, m));
- } catch (IllegalArgumentException e) {
- throw new RuntimeException("IllegalArgumentException:" + e + "\nMethods:" + m.getName());
- } catch (InvocationTargetException e) {
- throw new RuntimeException("InvocationTargetException:" + e + "\nMethods:" + m.getName());
- }
- }
- }
- return o;
- }
- /***
- *
- * 把数据库的一条记录映射到相应的dao对象中,
- * 如果dao中的字段与数据库字段不一致,返回的就是dao数据类型定义的默认值
- * 如:dao的字段long vehicleID;而数据库的字段是vehicle_id,那么返回的
- * 就定义的默认值0.
- * @param rs 查询的结果集
- * @param c 结果集一条记录,而一条记录所对应的dao类
- * @return
- * @throws SQLException
- * @throws IllegalAccessException
- * @throws InstantiationException
- */
- private static Object initObjectFromRsIfExist(ResultSet rs, Class<?> c) throws SQLException, IllegalAccessException, InstantiationException{
- Object o = c.newInstance();//一条记录的dao,新建对象
- Method[] methods = o.getClass().getMethods();//dao对象所有的方法
- String field;
- for(Method m: methods){
- //得到dao字段,如getRegdate,转换成Regdate
- field = m.getName().substring(3);
- //查询dao映射的字段是否在记录在数据库包含的字段,dao方法对set开头的方法进行处理
- //因为要将结果集映射到dao里面
- if(m.getName().startsWith("set") && rsContainsFields(rs, field)){
- try {
- m.invoke(o, getParamValueFromRs(rs, m));
- } catch (IllegalArgumentException e) {
- throw new RuntimeException("IllegalArgumentException:" + e + "\nMethods:" + m.getName());
- } catch (InvocationTargetException e) {
- throw new RuntimeException("InvocationTargetException:" + e + "\nMethods:" + m.getName());
- }
- }
- }
- return o;
- }
- /***
- *
- * @param rs 查询的结果集
- * @param m dao映射字段对应的一个set方法
- * @return
- * @throws SQLException
- */
- private static Object getParamValueFromRs(ResultSet rs, Method m) throws SQLException
- {
- String fieldName = m.getName().substring(3);
- Type type = m.getGenericParameterTypes()[0];//获取set方法参数的类型
- return getValueFromRs(rs, fieldName, type);
- }
- /**
- * 获取数据库一条记录的一个列值
- * @param rs 查询的结果集
- * @param fieldName dao数据字段,也就是数据库记录的数据字段类型
- * @param t 参数的数据类型
- * @return
- * @throws SQLException
- */
- private static Object getValueFromRs(ResultSet rs, String fieldName, Type t) throws SQLException{
- String type = t.toString();
- try{
- if(type.equals("int") || type.equals("class java.lang.Integer")){
- return rs.getInt(fieldName);
- }else if(type.equals("float") || type.equals("class java.lang.Float")){
- return rs.getFloat(fieldName);
- }else if(type.equals("double") || type.equals("class java.lang.Double")){
- return rs.getDouble(fieldName);
- }else if(type.equals("long") || type.equals("class java.lang.Long")){
- return rs.getLong(fieldName);
- }else if(type.equals("class java.lang.String")){
- return rs.getString(fieldName);
- }else if(type.equals("class java.sql.Timestamp")){
- return rs.getTimestamp(fieldName);
- }else if(type.equals("class java.sql.Date")){
- return rs.getDate(fieldName);
- }else if(type.equals("class java.sql.Time")){
- return rs.getTime(fieldName);
- }
- }catch(SQLException e){
- throw new SQLException("SQLException when get field:" + fieldName + "\n" + e);
- }
- throw new RuntimeException("getValueFromRsByField fail, field type is:" + type + ",field name is:" + fieldName);
- }
- /***
- * 关闭数据库多个结果集
- * @param rss
- */
- public static void closeRs(ResultSet... rss){
- for(ResultSet rs: rss){
- if(rs != null){
- try {
- rs.close();
- } catch (SQLException e) {
- }
- }
- }
- }
- /**
- * 关闭数据库多个psts
- * @param psts
- */
- public static void closePst(Statement... psts){
- for(Statement pst: psts){
- if(pst != null){
- try {
- pst.close();
- } catch (SQLException e) {
- }
- }
- }
- }
- /**
- * 关闭数据库所得到的多个链接
- * @param cons
- */
- public static void closeCon(Connection... cons){
- for(Connection con: cons){
- if(con != null)
- {
- try {
- con.close();
- } catch (SQLException e) {
- }
- }
- }
- }
- }
连接Oracle数据库类
- package com.hewen.dao.manage;
- import java.sql.Connection;
- import java.sql.DriverManager;
- import java.sql.SQLException;
- /***
- * 这个是连接Oracle数据库
- * @author Administrator
- *
- */
- public class DBTest {
- public static Connection getCon() throws SQLException{
- try {
- Class.forName("oracle.jdbc.driver.OracleDriver");
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- return null;
- }
- String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
- String user = "avls";
- String password = "1";
- return DriverManager.getConnection(url, user, password);
- }
- }
封装的dao类
- package com.hewen.dao.manage;
- import java.sql.Date;
- import java.util.ArrayList;
- import java.util.List;
- public class Vehicle{
- private long vehicle_Id;//车牌ID
- private String number_plate;//车牌号码
- private String def_flag;//车牌自定义别名
- private int number_plate_type_id;//拍照类型id
- private int kind_id;//车辆类型ID,如物流、出租等
- private String style;//车辆品牌如:夏利、奔驰、本田等
- private String color;//车辆颜色
- private String sn;//序列号
- private String interphoneid;//对讲机身份码
- private String interphoneno;//对讲机号
- private int channelno;//频道号
- private float initdistance;//初始里程
- private Date lastmaintaintime;//最后保养时间
- private String vehiclestate;//车辆状态,如正常使用,作废等
- private Date buydate;//购买时间
- private Date usedate;//使用时间
- private Date regdate;//登记时间
- private int isdeleted;//是否删除
- private Date deletedate;//删除时间
- private Date last_update_time;//最后更新时间
- private String remark;//备注
- private Date stamp;//入库时间
- private String superviser;//责任人姓名
- private String tel;//责任人电话一
- private String tel2;//责任人电话2
- public String getRemark() {
- return remark;
- }
- public void setRemark(String remark) {
- this.remark = remark;
- }
- public String toString(){
- return "vehicle_id: "+this.vehicle_Id+" numberPlate: "+this.number_plate+" deleteDate: "+this.deletedate;
- }
- //@Override
- public String tagetTableName() {
- return "t_used_vehicle";
- }
- //@Override
- public List<String> unEditFields() {
- List<String> list = new ArrayList<String>();
- list.add("remark");
- return list;
- }
- public String getNumber_plate() {
- return number_plate;
- }
- public void setNumber_plate(String number_plate) {
- this.number_plate = number_plate;
- }
- public String getDef_flag() {
- return def_flag;
- }
- public void setDef_flag(String def_flag) {
- this.def_flag = def_flag;
- }
- public int getNumber_plate_type_id() {
- return number_plate_type_id;
- }
- public void setNumber_plate_type_id(int number_plate_type_id) {
- this.number_plate_type_id = number_plate_type_id;
- }
- public int getKind_id() {
- return kind_id;
- }
- public void setKind_id(int kind_id) {
- this.kind_id = kind_id;
- }
- public String getStyle() {
- return style;
- }
- public void setStyle(String style) {
- this.style = style;
- }
- public String getColor() {
- return color;
- }
- public void setColor(String color) {
- this.color = color;
- }
- public String getSn() {
- return sn;
- }
- public void setSn(String sn) {
- this.sn = sn;
- }
- public String getInterphoneid() {
- return interphoneid;
- }
- public void setInterphoneid(String interphoneid) {
- this.interphoneid = interphoneid;
- }
- public String getInterphoneno() {
- return interphoneno;
- }
- public void setInterphoneno(String interphoneno) {
- this.interphoneno = interphoneno;
- }
- public int getChannelno() {
- return channelno;
- }
- public void setChannelno(int channelno) {
- this.channelno = channelno;
- }
- public float getInitdistance() {
- return initdistance;
- }
- public void setInitdistance(float initdistance) {
- this.initdistance = initdistance;
- }
- public Date getLastmaintaintime() {
- return lastmaintaintime;
- }
- public void setLastmaintaintime(Date lastmaintaintime) {
- this.lastmaintaintime = lastmaintaintime;
- }
- public String getVehiclestate() {
- return vehiclestate;
- }
- public void setVehiclestate(String vehiclestate) {
- this.vehiclestate = vehiclestate;
- }
- public Date getBuydate() {
- return buydate;
- }
- public void setBuydate(Date buydate) {
- this.buydate = buydate;
- }
- public Date getUsedate() {
- return usedate;
- }
- public void setUsedate(Date usedate) {
- this.usedate = usedate;
- }
- public Date getRegdate() {
- return regdate;
- }
- public void setRegdate(Date regdate) {
- this.regdate = regdate;
- }
- public int getIsdeleted() {
- return isdeleted;
- }
- public void setIsdeleted(int isdeleted) {
- this.isdeleted = isdeleted;
- }
- public Date getDeletedate() {
- return deletedate;
- }
- public void setDeletedate(Date deletedate) {
- this.deletedate = deletedate;
- }
- public Date getLast_update_time() {
- return last_update_time;
- }
- public void setLast_update_time(Date last_update_time) {
- this.last_update_time = last_update_time;
- }
- public Date getStamp() {
- return stamp;
- }
- public void setStamp(Date stamp) {
- this.stamp = stamp;
- }
- public String getSuperviser() {
- return superviser;
- }
- public void setSuperviser(String superviser) {
- this.superviser = superviser;
- }
- public String getTel() {
- return tel;
- }
- public void setTel(String tel) {
- this.tel = tel;
- }
- public String getTel2() {
- return tel2;
- }
- public void setTel2(String tel2) {
- this.tel2 = tel2;
- }
- public long getVehicle_Id() {
- return vehicle_Id;
- }
- public void setVehicle_Id(long vehicle_Id) {
- this.vehicle_Id = vehicle_Id;
- }
- }
运行的结果
- [{vehiclestate=待命状态(对应现场返回), vehicle_id=2, interphoneid=null, deletetime=null, number_plate=苏B10001, regdate=null, initdistance=0, superviser=null, style=null, number_plate_type_id=4, tel=null, buydate=2010-02-26, isdeleted=0, kind_id=1, channelno=1, usedate=2010-02-26, remark=null, sn=陆震,(822)22911,13771000789, last_update_time=2010-02-26, interphoneno=null, color=null, tel2=null, stamp=2010-02-26, lastmaintaintime=null, def_flag=null}, {vehiclestate=待命状态(对应现场返回), vehicle_id=3, interphoneid=null, deletetime=null, number_plate=苏B90003, regdate=null, initdistance=0, superviser=杨兴华, style=面包车, number_plate_type_id=4, tel=22916, buydate=2010-02-26, isdeleted=0, kind_id=3, channelno=1, usedate=2010-02-26, remark=null, sn=陆震,(822)22911,13771000789, last_update_time=2010-02-26, interphoneno=null, color=白, tel2=13151000793, stamp=2010-02-26, lastmaintaintime=null, def_flag=null}]
- vehicle:vehicle_id: 2 numberPlate: 苏B10001 deleteDate: null
- vehicle:vehicle_id: 3 numberPlate: 苏B90003 deleteDate: null
- [vehicle_id: 2 numberPlate: 苏B10001 deleteDate: null,
- vehicle_id: 3 numberPlate: 苏B90003 deleteDate: null]