一、业务阐述
在开发中查询的数据库结果集,既要连接数据库、执行数据库操作、关闭数据库,还要把结果集的记录人为的设置到自己封装的DAO中等一系列的重复代码。
本文主要是想解决:用户只需要得到数据库连接,写sql语句,自己封装dao,其余的操作由封转的小框架解决这些重复的工作,用户得到的只是一个集合List。
List里面的元素有集合Map其中key是数据库中的字段类型,value是字段类型对应的值这个函数
DBUtil.executeQuery(con, sql)
List还提供集合元素存放的是dao对象,一条数据库记录对应一个dao对象,此函数是
DBUtil.executeQuery(con, sql,Vehicle.class)
以下提供源码的叙述
二、源码解说
测试类
Main.java代码
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类
Java代码
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> 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 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> getListFromRs(ResultSet rs) throws SQLException{
ResultSetMetaData md = rs.getMetaData();//得到结果集列的属性
int columns = md.getColumnCount();//得到记录有多少列
int i;
List> list = new ArrayList>();
while(rs.next()){
Map map = new HashMap();
for(i = 0; 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> getListFromRsLowerCase(ResultSet rs) throws SQLException{
ResultSetMetaData md = rs.getMetaData();
int columns = md.getColumnCount();
int i;
List> list = new ArrayList>();
while(rs.next()){
Map map = new HashMap();
for(i = 0; 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> getListFromRsUpperCase(ResultSet rs) throws SQLException{
ResultSetMetaData md = rs.getMetaData();
int columns = md.getColumnCount();
int i;
List> list = new ArrayList>();
while(rs.next()){
Map map = new HashMap();
for(i = 0; 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 getListFromRs(ResultSet rs, Class> c) throws SQLException{
List list = new ArrayList();
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
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数据库类
Dbtest.java代码
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类
Vehicle.java代码
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 unEditFields() {
List list = new ArrayList();
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]