JDBC模板类(version 1.2)
1.2版本中添加了一个新插入的方法: /** * 在Web开发中struts框架中,页数数据在被存入数据库时会被包装在一个formbean对象中 * 在把这些数据存入数据库时,需要把formbean中值取出来,在插入数据库中这样很麻烦 * 所以我设计了这个方法,只需要一个sql语句(sql语句字段名必须和数据库中的完全一致,字段顺序可以随便) * 和一个封装好数据对象。 * 这个方法对页面数据提交在存入数据库,有很大方便。 * 在这里插入主键时,主键值也应当包含那个封装对象中 * 思想:主要是对sql语句进行分析,解析出要插入字段名称,在利用反射技术将值set到preparedStatement对象中。 * @param sql 数据库插入 sql语句 * @param obj 已经封装好数据对象 * @return 新增成功记录数 * @throws Exception */ public int insert(String sql, Object obj) throws Exception { if(obj==null){ return 0; } Connection conn=null; PreparedStatement ps=null; ResultSet rs=null; String [] fieldNames=resolveSQL(sql); try { conn=jdbcUtil.getConnection(); ps=jdbcUtil.scrollReadOnlyResultSet(sql,conn); for(int i=0;i<fieldNames.length;i++){ Object o=valueFromObject(fieldNames[i],obj); PreparedStatementSetValue(ps,o,i+1); } return ps.executeUpdate(); }finally{ jdbcUtil.free(rs,ps,conn); } }
?
=================================================================
package daoUtil.daoTemplate;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.ArrayList;import java.util.Collection;import jdbcUtil.JdbcUtil;import daoUtil.PrimaryKeyer;import daoUtil.RowMapper;/** * 在写jdbc程序是可以清楚的知道 * 在程序中只有sql语句和其参数值是变化 * 其余程序代码几乎类似(获得连接,关闭连接) * 在这里我对以前所写jdbc程序进行了一下改进 * 将获得连接和关闭连接的程序代码交给一个模板类去做 * 再写jdbc程序时,调用模板类中相应的方法,传入sql语句和其参数值 * 这样大大简化jdbc程序,给我们带来方便 * 程序新版本往后日子会不断更新,渴望javaeye里面高手多多给我指点 * @author kevin.wangwei * Email:wanwei.234@163.com * 2010-1-30 */public class DAOTemplate{ /**jdbc工具类*/ private JdbcUtil jdbcUtil=JdbcUtil.getInstance(); /** * 数据库删除操作 * @param sql 删除操作sql语句 * @param args 删除操作sql语句参数值数组 * @return 删除记录条数 * @throws SQLException */ public int delete(String sql, Object[] args) throws SQLException { if(args==null||args.length==0){ return 0; } Connection conn=null; PreparedStatement ps=null; ResultSet rs=null; try { conn=jdbcUtil.getConnection(); ps=jdbcUtil.scrollReadOnlyResultSet(sql,conn); for(int i=0;i<args.length;i++){ ps.setObject(i+1,args[i]);//在这里我们应该调用下面的PreparedStatementSetValue方法, //不过这样写亦可以,但它不可以处理null值 } return ps.executeUpdate(); }finally{ jdbcUtil.free(rs,ps,conn); } } /** * 数据库更新操作 * @param sql 更新操作sql语句 * @param args sql语句参数值数组 * @return 更新记录条数 * @throws SQLException */ public int update(String sql, Object[] args) throws SQLException { if(args==null||args.length==0){ return 0; } Connection conn=null; PreparedStatement ps=null; ResultSet rs=null; try { conn=jdbcUtil.getConnection(); ps=jdbcUtil.scrollReadOnlyResultSet(sql,conn); for(int i=0;i<args.length;i++){ ps.setObject(i+1,args[i]); } return ps.executeUpdate(); }finally{ jdbcUtil.free(rs,ps,conn); } } /** * 数据库查询操作 采用反射来给包装sql语句参数赋值 * @param sql 查询操作sql语句 * @param args 删除操作sql语句数组数值 * @return 结果对象 * @throws SQLException */ public Object find(String sql, Object[] args,RowMapper rowMapper) throws SQLException { if(args==null||args.length==0){ return 0; } Connection conn=null; PreparedStatement ps=null; ResultSet rs=null; try { conn=jdbcUtil.getConnection(); ps=jdbcUtil.scrollReadOnlyResultSet(sql,conn); for(int i=0;i<args.length;i++){ try { PreparedStatementSetValue(ps,args[i],i+1); } catch (Exception e) { e.printStackTrace(); } } rs=ps.executeQuery(); Object obj=null; while(rs.next()){ obj=rowMapper.rowMapping(rs); } return obj; }finally{ jdbcUtil.free(rs,ps,conn); } } /** * 获得表中记录数 * @param sql sql语句 * @param args 参数数组 * @return 表中记录数 * @throws SQLException */ public int getRecordCount(String sql, Object[] args) throws SQLException { if(args==null||args.length==0){ return 0; } int count=0; Connection conn=null; PreparedStatement ps=null; ResultSet rs=null; try { conn=jdbcUtil.getConnection(); ps=jdbcUtil.scrollReadOnlyResultSet(sql,conn); for(int i=0;i<args.length;i++){ ps.setObject(i+1,args[i]); } rs=ps.executeQuery(); if(rs.next()){ count=rs.getInt(1); } }finally{ jdbcUtil.free(rs,ps,conn); } return count; } /** * 根据数据库表名,找到该表中所有记录数 * @param tableName 要查询的表 * @return 表中记录数 * @throws SQLException */ public int getRecordCount(String tableName) throws SQLException { if(tableName==null||tableName.equals("")){ return 0; } int count=0; Connection conn=null; PreparedStatement ps=null; ResultSet rs=null; try { conn=jdbcUtil.getConnection(); String sql="select count(*) from "+tableName; ps=jdbcUtil.scrollReadOnlyResultSet(sql,conn); if(rs.next()){ count=rs.getInt(1); } }finally{ jdbcUtil.free(rs,ps,conn); } return count; } /** * 数据库插入操作(这是采用接口回调技术,由调用程序来给主键赋值) * @param sql 插入操作 sql语句 * @param args 插入数 * @param primaryIndex 主键在sql语句中位置(小于-1表示用数据自动生成主键不需要插入) * @return 插入记录数 * @throws Exception */ public int insert(String sql, Object[] args, int primaryKeyIndex,PrimaryKeyer primaryKeyer) throws Exception { if(args==null||args.length==0){ return 0; } Connection conn=null; PreparedStatement ps=null; ResultSet rs=null; try { conn=jdbcUtil.getConnection(); ps=jdbcUtil.scrollReadOnlyResultSet(sql,conn); if(primaryKeyIndex<=-1){ for(int i=0;i<args.length;i++){ try { PreparedStatementSetValue(ps,args[i],i+1); } catch (Exception e) { e.printStackTrace(); } } }else if(primaryKeyIndex>-1&&primaryKeyIndex<args.length){ for(int i=0;i<args.length;i++){ if(i==primaryKeyIndex){ PreparedStatementSetValue(ps,primaryKeyer.getPrimaryKey(),i+1); //ps.setObject(i+1,primaryKeyer.getPrimaryKey()); }else{ PreparedStatementSetValue(ps,args[i],i+1); } } }else{ throw new IllegalArgumentException("设置主键位置不正确!"); } return ps.executeUpdate(); }finally{ jdbcUtil.free(rs,ps,conn); } } /** * 在Web开发中struts框架中,页数数据在被存入数据库时会被包装在一个formbean对象中 * 在把这些数据存入数据库时,需要把formbean中值取出来,在插入数据库中这样很麻烦 * 所以我设计了这个方法,只需要一个sql语句(sql语句字段名必须和数据库中的完全一致,字段顺序可以随便) * 和一个封装好数据对象。 * 这个方法对页面数据提交在存入数据库,有很大方便。 * 在这里插入主键时,主键值也应当包含那个封装对象中 * 思想:主要是对sql语句进行分析,解析出要插入字段名称,在利用反射技术将值set到preparedStatement对象中。 * @param sql * @param obj * @return * @throws Exception */ public int insert(String sql, Object obj) throws Exception { if(obj==null){ return 0; } Connection conn=null; PreparedStatement ps=null; ResultSet rs=null; String [] fieldNames=resolveSQL(sql); try { conn=jdbcUtil.getConnection(); ps=jdbcUtil.scrollReadOnlyResultSet(sql,conn); for(int i=0;i<fieldNames.length;i++){ Object o=valueFromObject(fieldNames[i],obj); PreparedStatementSetValue(ps,o,i+1); } return ps.executeUpdate(); }finally{ jdbcUtil.free(rs,ps,conn); } } /** * 查找符合条件所有记录(这也是采用接口回调技术,由调用程序来决定结果set到什么对象中) * @param sql 查询sql语句 * @param args 查询参数 * @param rowMapper 结果集映射器 * @return Collection 记录集 * @throws SQLException */ public Collection ObjectList(String sql, Object[] args,RowMapper rowMapper) throws SQLException { if(args==null||args.length==0){ return null; } Connection conn=null; PreparedStatement ps=null; ResultSet rs=null; Collection list=null; try { conn=jdbcUtil.getConnection(); ps=jdbcUtil.scrollReadOnlyResultSet(sql,conn); for(int i=0;i<args.length;i++){ ps.setObject(i+1,args[i]); } list=new ArrayList(); rs=ps.executeQuery(); while(rs.next()){ Object obj=rowMapper.rowMapping(rs); list.add(obj); } }finally{ jdbcUtil.free(rs,ps,conn); } return list; } /** * 依据与表对应的JavaBean的Class(采用反射技术将结果集set到JavaBean对象中) * 将查询结果封装为一个JavaBean的对象返回 * @param sql 查询sql语句 * @param args 查询参数 * @param javaBeanClass JavaBean的Class * @return 返回获得JavaBean对象 * @throws Exception */ public Object find(String sql, Object[] args,Class javaBeanClass) throws Exception { if(args==null||args.length==0){ return 0; } Connection conn=null; PreparedStatement ps=null; ResultSet rs=null; try { conn=jdbcUtil.getConnection(); ps=jdbcUtil.scrollReadOnlyResultSet(sql,conn); for(int i=0;i<args.length;i++){ ps.setObject(i+1,args[i]); } rs=ps.executeQuery(); String[] names=jdbcUtil.getResultSetFieldName(rs); Object obj=null; while(rs.next()){ obj=rowMapper(javaBeanClass,rs,names); } return obj; }finally{ jdbcUtil.free(rs,ps,conn); } } /** * 依据与表对应的JavaBean的Class(上面方法重载方法,采用了不同实现机制) * 将查询结果封装为一个包含JavaBean的集合对象返回 * @param sql 查询sql语句 * @param args 查询参数 * @param javaBeanClass javaBeanClass JavaBean的Class * @return 记录集 * @throws Exception */ public Collection ObjectList(String sql, Object[] args,Class javaBeanClass) throws Exception { if(args==null||args.length==0){ return null; } Connection conn=null; PreparedStatement ps=null; ResultSet rs=null; Collection list=null; try { conn=jdbcUtil.getConnection(); ps=jdbcUtil.scrollReadOnlyResultSet(sql,conn); for(int i=0;i<args.length;i++){ ps.setObject(i+1,args[i]); } list=new ArrayList(); rs=ps.executeQuery(); String[] names=jdbcUtil.getResultSetFieldName(rs); while(rs.next()){ Object obj=rowMapper(javaBeanClass,rs,names); list.add(obj); } }finally{ jdbcUtil.free(rs,ps,conn); } return list; } /** * 这个方法是通过反射来将数据库表中对应的javaBean对象set值 * 该JavaBean对象必须有一个无参数的构造函数 * @param clazz javabean 超类 * @param rs 数据库结果集 * @return Object 对象 * @throws Exception */ private Object rowMapper(Class clazz,ResultSet rs,String[] names) throws Exception{ Object obj=clazz.newInstance(); for(int i=0;i<names.length;i++){ String columnName=toUpperCaseFirstLetterForSet(names[i]); Method[] m=clazz.getMethods(); for(int j=0;j<m.length;j++){ String methodName=m[j].getName(); if(columnName.equals(methodName)){ m[j].invoke(obj,rs.getObject(i+1)); break; } } } return obj; } /** * 将字符串一个字母转换为大写 * @param name * @return */ private String toUpperCaseFirstLetterForSet(String name){ if(name!=null&&name.length()>0){ return "set"+name.substring(0,1).toUpperCase()+name.substring(1); } return ""; } /** * 这是采用反射的方法来给PreparedStatement包装sql 语句参数赋值 * @param ps * @param obj 数组中对象 * @param index 参数索引位置 * @throws Exception */ private void PreparedStatementSetValue(PreparedStatement ps,Object obj,int index) throws Exception{ String name=getMethodName(obj); Method[] m=ps.getClass().getMethods(); for(int i=0;i<m.length;i++){ String methodName=m[i].getName(); if(name.equals(methodName)){ //System.out.println(methodName+"==========="); m[i].invoke(ps,index,obj); break; } } } /** * 通过反射获得数组中每个元素类型, * 从而获得PreparedStatement对象setxxx方法名称 * @param obj sql语句参数值 * @return PreparedStatement对象要调用setxxx方法名称 */ private String getMethodName(Object obj){ if(obj==null){ return null; } //System.out.println(obj+"==========="); String className=obj.getClass().getName(); String[] names=className.split("\\."); className=names[names.length-1]; if(className.equalsIgnoreCase("Integer")){ className="Int"; } className="set"+className; return className; } /** * 从sql语句中解析出我们需要字段名称 * @param sql 必须是一个有效 sql插入语句(最好不要用别名) * @return 字段名称数组 */ private String[] resolveSQL(String sql){ sql=sql.toLowerCase(); int left_brackets=sql.indexOf("("); int right_brackets=sql.indexOf(")"); String fieldString=sql.substring(left_brackets+1,right_brackets); String[] fieldNames=fieldString.split(","); return fieldNames; } /** * 根据字段名从包装数据对象中取出于该字段相对应的值 * 通过反射用get方法来获得 * @param fieldName * @return * @throws InvocationTargetException * @throws IllegalAccessException * @throws Exception */ private Object valueFromObject(String fieldName,Object formBean) throws Exception{ String methodName=toUpperCaseFirstLetterForGet(fieldName); Method[] methods=formBean.getClass().getMethods(); for(Method m:methods){ String mName=m.getName(); if(methodName.equals(mName)){ Object value=m.invoke(formBean); return value; } } return null; } /** * 将字符串一个字母转换为大写 * @param name * @return */ private String toUpperCaseFirstLetterForGet(String name){ if(name!=null&&name.length()>0){ name=name.trim(); return "get"+name.substring(0,1).toUpperCase()+name.substring(1); } return ""; }}
?
2 楼 zhangskills 2010-02-20 没想到也有人这么想的,我也写了一个类似的,一直怕别人笑我的思路,今天也发上来,有空指点指点,呵呵