- 浏览: 762317 次
- 性别:
- 来自: 深圳
文章分类
- 全部博客 (241)
- 个人思考 (1)
- 数据库 (5)
- java基础 (32)
- 软件工程 (2)
- zk开源框架 (15)
- 设计模式 (25)
- javascript (12)
- css (9)
- UML (2)
- CMMI软件需求 (3)
- CMMI软件设计 (2)
- CMMI软件实现 (1)
- CMMI软件测试 (1)
- 正则表达式 (4)
- 系统日志配置 (4)
- 应用服务器 (1)
- spring (7)
- XML (6)
- java web (10)
- Ajax (3)
- RichFaces (14)
- 问题 (1)
- 评论文章 (2)
- fushioncharts (2)
- MAVN (4)
- jquery (26)
- Ext js学习 (2)
- 学习心得 (2)
- CSS兼容问题 (3)
- XSL-FOP (1)
- Quartz (0)
- OSGI (1)
- spring--security (6)
- apache tools (1)
- eclispe 小技巧 (2)
- Ant (1)
- 杂记 (1)
- spring3系列 (5)
- java cache (4)
- EffectiveJava (2)
- 代码重构 (0)
最新评论
-
psz6696:
可以说是超级简单的Demo了,可惜没有演示设值注入和构造注入两 ...
模拟spring中的ClassPathXmlApplicationContext类的实现 -
ziyourJava:
[flash=200,200][img][url][list] ...
spring security进级篇 V 自定义标签控制显示 -
ztw1122:
...
zk组件开发指南(目录) -
zjysuv:
容我说一句 在座的各位都是垃圾 spring 3.2以后的@C ...
三. spring mvc 异常统一处理 -
chengwu1201:
二 基于Spring的异常体系处理
虽然DAO模式已经有了好多的成熟的框架,但它仍然是一个比较重要的设计模式。要做一个比较合理的DAO模式,你需要对工厂模式、单例模式、模板模式、策略模式、代理模式、泛型、反射机制、输入输出、异常等知识比较熟悉。下面结合自己理解,设计一个DAO设计模式的例子,希望大家给与指正。
1、数据库连接池的工具类。
在数据库连接池的工具类中,采用了开源的DBCP数据库连接池,调用了DataSource接口,DBCP中关于Datasource的Connection采用了动态代理的方式实现,在这里只是提出,感兴趣可以查看其源码,该工具类采用可配置的方式实现的,代码如下:
package com.cvicse.utils; import java.io.InputStream; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSourceFactory; /** * 数据库连接池操作工具类 * */ public class JDBCUtils { private static DataSource myDataSource = null; private JDBCUtils() { } static { try { Properties prop = new Properties(); //采用了类的加载获取路径下数据库的配置信息 InputStream is = JDBCUtils.class.getClassLoader() .getResourceAsStream("dbcpconfig.properties"); prop.load(is); myDataSource = BasicDataSourceFactory.createDataSource(prop); } catch (Exception e) { throw new ExceptionInInitializerError(e); } } /** * 获取数据源 * * @return */ public static DataSource getDataSource() { return myDataSource; } /** * 获取连接 * * @return * @throws SQLException */ public static Connection getConnection() throws SQLException { return myDataSource.getConnection(); } /** * 关闭资源 * @param rs * @param st * @param conn * @throws SQLException */ public static void free(ResultSet rs, Statement st, Connection conn) throws SQLException { try { if (rs != null) rs.close(); } catch (SQLException e) { throw new SQLException(); } finally { try { if (st != null) st.close(); } catch (SQLException e) { throw new SQLException(); } finally { if (conn != null) try { conn.close(); } catch (Exception e) { throw new SQLException(); } } } } }
数据库配置文件的信息如下dbcpconfig.properties
#连接设置 driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/test123 username=root password= #<!-- 初始化连接 --> initialSize=10 #最大连接数量 maxActive=50 #<!-- 最大空闲连接 --> maxIdle=20 #<!-- 最小空闲连接 --> minIdle=5 #<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 --> maxWait=60000 #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;] #注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。 connectionProperties=useUnicode=true;characterEncoding=UTF-8 #指定由连接池所创建的连接的自动提交(auto-commit)状态。 defaultAutoCommit=true #driver default 指定由连接池所创建的连接的只读(read-only)状态。 #如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix) defaultReadOnly= #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。 #可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE defaultTransactionIsolation=READ_UNCOMMITTED
2、异常定义,用于处理DAO层的异常类,因为异常最好要在业务层进行处理,个人认为这DAO层异常应该在业务层进行处理,所以DAO层的必要异常都抛出。
package com.cvicse.dao.exception; /** * * 定义DAO异常类 * */ public class DaoException extends Exception { private static final long serialVersionUID = 1L; /** * @param message * @param cause */ public DaoException(String message, Throwable cause) { super(message, cause); } /** * @param message */ public DaoException(String message) { super(message); } } package com.cvicse.dao.exception; /** * 传入参数错误异常 * */ public class DaoParameterException extends DaoException { private static final long serialVersionUID = 1L; /** * @param message * @param cause */ public DaoParameterException(String message, Throwable cause) { super(message, cause); } /** * @param message */ public DaoParameterException(String message) { super(message); } }
3、定义要操作的pojo类,这里定义了2个pojo类
package com.cvicse.po; /** * 课程持久层对象 * */ public class Course { private long id; private String name; /** * 构造函数类 */ public Course() { this.id = 0; this.name = null; } /** * @param id * @param name */ public Course(long id, String name) { this.id = id; this.name = name; } /** * @return */ public long getId() { return id; } /** * @param id */ public void setId(long id) { this.id = id; } /** * @return */ public String getName() { return name; } /** * @param name */ public void setName(String name) { this.name = name; } } package com.cvicse.po; /** * 学生持久层对象 */ public class Student { private long id; private String name; public Student() { this.id = 0; this.name = null; } public Student(long id, String name) { this.id = id; this.name = name; } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
4、定义对象操作的DAO接口,因为面向接口编程,定义接口目的是DAO层的操作能和业务层解耦。
package com.cvicse.dao; import java.util.List; import com.cvicse.dao.exception.DaoException; import com.cvicse.po.Course; /** * 课程DAO层接口 * */ public interface CourseDAO { /** * 获取列表 * @return * @throws DaoException */ public List<Course> selectCourses() throws DaoException; /** * 插入记录 * @param course * @throws DaoException */ public void insertCourse(Course course) throws DaoException; } package com.cvicse.dao; import java.util.List; import com.cvicse.dao.exception.DaoException; import com.cvicse.po.Student; public interface StudentDAO { /** * 查询方法 * @return * @throws DaoException */ public List selectStudents() throws DaoException; /** * 添加方法 * @param student * @throws DaoException */ public void insertStudent(Student student) throws DaoException; /** * 删除方法 * @param student * @throws DaoException */ public void deleteStudent(Student student) throws DaoException; /** * 修改方法 * @param student * @throws DaoException */ public void modifyStudent(Student student) throws DaoException; }
5、定义DAO操作的模板类,将DAO层的常用操作类进行提取。
package com.cvicse.util; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; import com.cvicse.dao.exception.DaoException; import com.cvicse.dao.exception.DaoParameterException; import com.cvicse.dao.refactor.RowMapper; public class DaoOperateTemplate { /** * 查找单个记录对象 * * @param sql * @param args * @param rowMapper * @return * @throws DaoException */ public Object find(String sql, Object[] args, RowMapper rowMapper) throws DaoException { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = JDBCUtils.getConnection(); ps = conn.prepareStatement(sql); for (int i = 0; i < args.length; i++) ps.setObject(i + 1, args[i]); rs = ps.executeQuery(); Object obj = null; if (rs.next()) { obj = rowMapper.mapRow(rs); } return obj; } catch (SQLException e) { throw new DaoException(e.getMessage(), e); } finally { try { JDBCUtils.free(rs, ps, conn); } catch (SQLException e) { throw new DaoParameterException(e.getMessage(), e); } } } /** * 查找多条记录对象 * * @param sql * @param args * @param rowMapper * @return * @throws DaoException */ public List<Object> Query(String sql, Object[] args, RowMapper rowMapper) throws DaoException { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; List<Object> results = new ArrayList<Object>(); try { conn = JDBCUtils.getConnection(); ps = conn.prepareStatement(sql); for (int i = 0; i < args.length; i++) ps.setObject(i + 1, args[i]); rs = ps.executeQuery(); Object obj = null; while (rs.next()) { obj = rowMapper.mapRow(rs); results.add(obj); } return results; } catch (SQLException e) { throw new DaoException(e.getMessage(), e); } finally { try { JDBCUtils.free(rs, ps, conn); } catch (SQLException e) { throw new DaoParameterException(e.getMessage(), e); } } } /** * 更新操作 * * @param sql * @param args * @param isGeneralKey * @throws DaoException */ public void update(String sql, Object[] args, boolean isGeneralKey) throws DaoException { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = JDBCUtils.getConnection(); ps = (isGeneralKey ? conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) : conn .prepareStatement(sql)); for (int i = 0; i < args.length; i++) ps.setObject(i + 1, args[i]); ps.executeUpdate(); } catch (SQLException e) { throw new DaoException(e.getMessage(), e); } finally { try { JDBCUtils.free(rs, ps, conn); } catch (SQLException e) { throw new DaoParameterException(e.getMessage(), e); } } } }
上面DAO通用操作类中定义接口,用于对象的转化。
package com.cvicse.dao.refactor; import java.sql.ResultSet; import java.sql.SQLException; /** * @author Administrator * */ public interface RowMapper { /** * 映射接口 * @param rs * @return * @throws SQLException */ public Object mapRow(ResultSet rs) throws SQLException; }
6、定义具体DAO的实现,在DAO具体实现中,我们采用组合的方式引用通用类,正如设计原则中说的先考虑组合后考虑继承。所以我们在这里选择组合,而不用继承,同时继承对象的转换同样会存在问题。在每个具体DAO操作的实现类中,我们采用了策略模式。
package com.cvicse.dao.impl; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import com.cvicse.dao.CourseDAO; import com.cvicse.dao.exception.DaoException; import com.cvicse.dao.refactor.RowMapper; import com.cvicse.po.Course; import com.cvicse.util.DaoOperateTemplate; public class CourseDAOImpl implements CourseDAO { private DaoOperateTemplate daoTemplate = new DaoOperateTemplate(); public void insertCourse(Course course) throws DaoException { // TODO Auto-generated method stub String sql = "insert into course(id,name) values (?,?) "; Object[] args = new Object[] { course.getId(), course.getName() }; daoTemplate.update(sql, args, false); } public List<Course> selectCourses() throws DaoException { // TODO Auto-generated method stub String sql = "select * from course where id=? "; Object[] args = new Object[] { 1 }; List courseList = daoTemplate.Query(sql, args, new courseRowMapper()); return courseList; } /** * 内部匿名类 * * @author Administrator * */ class courseRowMapper implements RowMapper { public Object mapRow(ResultSet rs) throws SQLException { Course course = new Course(); course.setId(rs.getLong("id")); course.setName(rs.getString("name")); return course; } } } package com.cvicse.dao.impl; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import com.cvicse.dao.StudentDAO; import com.cvicse.dao.exception.DaoException; import com.cvicse.dao.refactor.RowMapper; import com.cvicse.po.Student; import com.cvicse.util.DaoOperateTemplate; public class StudentDAOImpl implements StudentDAO { private DaoOperateTemplate daoTemplate = new DaoOperateTemplate(); /* * (non-Javadoc) * * @see com.cvicse.dao.StudentDAO#deleteStudent(com.cvicse.po.Student) */ public void deleteStudent(Student student) throws DaoException { // TODO Auto-generated method stub String sql = "delete from user where id=?"; Object[] args = new Object[] { student.getId() }; daoTemplate.update(sql, args, false); } /* * (non-Javadoc) * * @see com.cvicse.dao.StudentDAO#insertStudent(com.cvicse.po.Student) */ public void insertStudent(Student student) throws DaoException { // TODO Auto-generated method stub String sql = "insert into student(id,name) values (?,?) "; Object[] args = new Object[] { student.getId(), student.getName() }; daoTemplate.update(sql, args, false); } public void modifyStudent(Student student) throws DaoException { // TODO Auto-generated method stub String sql = "update student set name=? where id=? "; Object[] args = new Object[] { student.getName(), student.getId() }; daoTemplate.update(sql, args, false); } public List selectStudents() throws DaoException { // TODO Auto-generated method stub String sql = "select * from course where id=? "; Object[] args = new Object[] { 1 }; List courseList = daoTemplate.Query(sql, args, new studentRowMapper()); return courseList; } /** * 内部匿名类 * * @author Administrator * */ class studentRowMapper implements RowMapper { public Object mapRow(ResultSet rs) throws SQLException { Student student = new Student(); student.setId(rs.getLong("id")); student.setName(rs.getString("name")); return student; } } }
7、我们定义工厂类,在定义工厂类,考虑到通用性,我们采用了反射机制加配置文件的形式来实现的。同时,在工厂模式中引入了饿汉式单例模式。
/** * */ package com.cvicse.daofactory; import java.io.IOException; import java.io.InputStream; import java.util.Properties; /** * 工厂类方法 * */ public class DaoFactory { private static DaoFactory instance = new DaoFactory();//懒汉法声明对象 private static Properties pro;// 配置文件对象 private DaoFactory() { try { // 初始化配置文件 pro = new Properties(); // 采用类加载器方法读取配置文件信息到字节流对象,采用类加载灵活,不用写死 InputStream inputStream = DaoFactory.class.getClassLoader() .getResourceAsStream("applicationContext.properties"); // 加载字节流对象 pro.load(inputStream); } catch (IOException e) { throw new ExceptionInInitializerError(e); } } /** * 单例模式获取唯一实例 * * @return */ public static DaoFactory getInstance() { return instance; } /** * 根据配置文件的名字获取类的名字,采用反射机制获取其对象 * * @param Key * @return */ public Object getDAO(String Key) throws Exception { String className = (String) pro.get(Key); return (Class.forName(className).newInstance()); } }
配置文件的内容如下:applicationContext.properties
courseDao=com.cvicse.dao.impl.CourseDAOImpl studentsDao=com.cvicse.dao.impl.StudentDAOImpl
8、业务层的调用方式,这里用客户端方式模拟的。在业务层通过接口的方式调用,使得DAO层和业务层能够解耦。
package com.cvicse.Test; import com.cvicse.dao.CourseDAO; import com.cvicse.daofactory.DaoFactory; /** * @author Administrator * */ public class ServiceClient { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub try { CourseDAO courseDao = (CourseDAO) DaoFactory.getInstance().getDAO( "courseDao"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
总结:在这个DAO设计模式中,涉及到很多java的基础知识,同时,也涉及太多的模式。只有灵活应用,才能体会的其中的灵活。关于DAO具体实现可以采用spring的simpetempate会更能简化其中的实现。
评论
spring在一定程度上会引起类的爆炸效应
一个不做j2ee的java程序员飘过。。。
啥叫Ioc, 你写业务代码的看那些有什么用。
spring在一定程度上会引起类的爆炸效应
一个不做j2ee的java程序员飘过。。。
2个字:流畅!
/** * 查找多条记录对象 * * @param sql * @param args * @param rowMapper * @return * @throws DaoException */ 这个方法弱弱的问一下楼主,如果是你写的一句SQL根据条件查询出来是100条,此时你如何确定你返回的List里面 就是100个元素? public List<Object> Query(String sql, Object[] args, RowMapper rowMapper) throws DaoException { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; List<Object> results = new ArrayList<Object>(); try { conn = JDBCUtils.getConnection(); ps = conn.prepareStatement(sql); for (int i = 0; i < args.length; i++) ps.setObject(i + 1, args[i]); rs = ps.executeQuery(); Object obj = null; while (rs.next()) { obj = rowMapper.mapRow(rs); results.add(obj); } return results; } catch (SQLException e) { throw new DaoException(e.getMessage(), e); } finally { try { JDBCUtils.free(rs, ps, conn); } catch (SQLException e) { throw new DaoParameterException(e.getMessage(), e); } } } /** * 更新操作 * * @param sql * @param args * @param isGeneralKey * @throws DaoException */ update方法都是清一色的void试问下你如果判断是否更改成功或者是你更改的条数? 有时候update不成功,但是他也不一定会catch到Exception,你想修改的效果没有达到,但程序没任何异常咋办? public void update(String sql, Object[] args, boolean isGeneralKey) throws DaoException { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = JDBCUtils.getConnection(); ps = (isGeneralKey ? conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) : conn .prepareStatement(sql)); for (int i = 0; i < args.length; i++) ps.setObject(i + 1, args[i]); ps.executeUpdate(); } catch (SQLException e) { throw new DaoException(e.getMessage(), e); } finally { try { JDBCUtils.free(rs, ps, conn); } catch (SQLException e) { throw new DaoParameterException(e.getMessage(), e); } } } }
1年多前的一个项目我也做过跟楼主类似的东西,但有个前提,那个项目禁止使用Hibernate,我提过多次建议都无效,最后没辙为了节省一下简单增删改查的代码量写了几个类。
1.Entity:所有实体实现这个接口。
public interface Entity<IDClass extends java.io.Serializable> { public IDClass getId(); public void setId(IDClass id); }
2.GenericDao:所有Dao实现这个接口。
public interface GenericDao<E extends Entity> { /** * 保存一个实体 * @param entity 实体对象 */ public void save(E entity); /** * 删除一个实体 * @param id 主键 */ public void delete(Serializable id); /** * 删除一个实体 * @param entity 实体对象 */ public void delete(E entity); /** * 批量删除实体 * @param entitiesId 实体编号数组 */ public void deleteBatchByEntitiesId(Object[] entitiesId); /** * 批量删除实体 * @param entities */ public void deleteBatchByEntities(List<E> entities); /** * 查询所有 * @param page 分页对象 * @param sorts 排序对象 * @return 查询结果 */ public List getAll(Page page, Sort... sorts); /** * 按页号和每页记录数查询所有 * @param pageIndex 页号 * @param pageSize 每页记录数 * @param sorts 排序 * @return 查询结果 */ public List getAll(Integer pageSize, Integer pageIndex, Sort... sorts); /** * 通过主键查询 * @param id 主键 * @return 实体对象 */ public E get(Serializable id); /** * 按页号和每页记录数查询结果 * @param ql 查询语句 * @param pageIndex 页号 * @param pageSize 每页记录数 * @param args 查询语句参数 * @return 查询结果 */ public List query(String ql, Integer pageSize, Integer pageIndex, Object ... args); /** * 通过查询语句查询 * @param ql 查询语句 * @param page 分页对象 * @param args 参数 * @return 查询结果 */ public List query(String ql, Page page, Object... args); /** * 通过查询语句查询,无分页操作 * @param ql 查询语句 * @param args 参数 * @return 查询结果 */ public List query(String ql, Object... args); /** * 执行更新 * @param ql 执行更新 * @param args ql参数 * @return 更新所影响的行数 */ public int update(String ql, Object... args); /** * 计算记录数 * @param ql 查询语句 * @param args 查询条件参数 * @return 符合条件的记录数 */ public int count(String ql, Object... args); }
3.EntityMapper:实体类属性到数据库表字段映射。
public class EntityMapper { // 类名 private Class entityClass; // 表明 private String tableName; // 列名为map键对应的字段名 private Map<String, String> columnMapField = new HashMap<String, String>(); // 字段名为map建对应的列名 private Map<String, String> fieldMapColumn = new HashMap<String, String>(); // get方法名称 private Map<String, String> gettersName = new HashMap<String, String>(); // set方法名称 private Map<String, String> settersName = new HashMap<String, String>(); // 被映射的字段个数 private Integer mappedColumnCount; // 数据库字段 private String[] columns; // 类字段 private String[] fields; // 类字段类型 private Class[] fieldsType; // 插入语句 private String insert; // 删除语句 private String delete; // 更新语句 private String update; // 查询语句 private String select; // 查询所有语句 private String all; // 匹配大写字母的正则 private static Pattern p = Pattern.compile("(_|[A-Z]+)"); // 日志 private static Log log = LogFactory.getLog(EntityMapper.class); protected static final Map<String, String> RS_METHOD_NAME; static{ RS_METHOD_NAME = new HashMap<String, String>(); RS_METHOD_NAME.put("byte", "getByte"); RS_METHOD_NAME.put("Byte", "getByte"); RS_METHOD_NAME.put("short", "getShort"); RS_METHOD_NAME.put("Short", "getShort"); RS_METHOD_NAME.put("int", "getInt"); RS_METHOD_NAME.put("Integer", "getInt"); RS_METHOD_NAME.put("long", "getLong"); RS_METHOD_NAME.put("Long", "getLong"); RS_METHOD_NAME.put("float", "getFloat"); RS_METHOD_NAME.put("Float", "getFloat"); RS_METHOD_NAME.put("double", "getDouble"); RS_METHOD_NAME.put("Double", "getDouble"); RS_METHOD_NAME.put("Date", "getTimestamp"); RS_METHOD_NAME.put("boolean", "getBoolean"); RS_METHOD_NAME.put("Boolean", "getBoolean"); RS_METHOD_NAME.put("String", "getString"); } /** * 构造方法初始化类与数据库表的映射关系 * @param className 类名 */ public EntityMapper(Class entityClass) throws SQLException{ this.entityClass = entityClass; this.tableName = convertName(entityClass.getSimpleName()); // 获得该实体类中所有字段名并按规则转换成数据库字段名装入到Map中 Field[] fields = entityClass.getDeclaredFields(); Map<String, String> fieldsMap = new HashMap<String, String>(); for(int i = 0; i < fields.length; i++){ fieldsMap.put(this.convertName(fields[i].getName()), fields[i].getName()); } Connection conn = null; ResultSet rs = null; try { conn = ((ConnectionProvider)Platform.getInstance().getBean("ConnectionProvider")).getConnection(); // 获得数据库中该表所有字段的元数据 DatabaseMetaData meta = conn.getMetaData(); rs = meta.getColumns(null, null, this.tableName, null); if(log.isDebugEnabled()){ log.debug(entityClass.getName() + " -> " + this.tableName); } List<String> columnsName = new ArrayList<String>(); List<String> fieldsName = new ArrayList<String>(); List<Class> fieldsType = new ArrayList<Class>(); String columnName = null; String fieldName = null; // 循环将数据库中与实体类中公有的字段放入Map while(rs.next()){ columnName = rs.getString(4); if((fieldName = fieldsMap.get(columnName)) != null){ if(log.isDebugEnabled()){ log.debug(entityClass.getName() + "." + fieldName + " -> " + this.tableName + "." + columnName); } this.columnMapField.put(columnName, fieldName); this.fieldMapColumn.put(fieldName, columnName); this.gettersName.put(fieldName, this.convertName("get", fieldName)); this.settersName.put(fieldName, this.convertName("set", fieldName)); columnsName.add(columnName); fieldsName.add(fieldName); fieldsType.add(this.entityClass.getDeclaredField(fieldName).getType()); } } this.columns = (String[])columnsName.toArray(new String[columnsName.size()]); this.fields = (String[])fieldsName.toArray(new String[fieldsName.size()]); this.fieldsType = (Class[])fieldsType.toArray(new Class[fieldsType.size()]); this.mappedColumnCount = this.columns.length; // 初始化CRUD语句 this.createInsert(); this.createDelete(); this.createUpdate(); this.createSelect(); } catch(Exception ex) { log.error("初始化实体映射类失败...",ex); } finally { try{ if(rs != null){ rs.close(); conn.close(); } }catch(Exception ex){ log.error(ex); } } } /** * 通过结果集创建实体类 * @param rs 结果集 * @return 实体类 */ public Entity createFromResultSet(ResultSet rs){ try{ Entity entity = null; if(rs.next()){ entity = (Entity)this.entityClass.newInstance(); for(int i = 0; i < fields.length; i++){ if(log.isDebugEnabled()){ Object value = rs.getClass().getMethod(RS_METHOD_NAME.get(fieldsType[i].getSimpleName()), String.class).invoke(rs, columns[i]); log.debug(this.entityClass.getName() + "." + fields[i] + " -> " + value + " : " + (value == null ? "null" : value.getClass().getName())); } this.entityClass.getMethod(this.setterName(fields[i]), fieldsType[i]).invoke(entity, rs.getClass().getMethod(RS_METHOD_NAME.get(fieldsType[i].getSimpleName()), String.class).invoke(rs, columns[i])); } } return entity; }catch(Exception ex){ log.warn("通过结果集创建实体类" + this.entityClass.getName() + "对象时发生错误!"); return null; } } /** * 将字段名转换为方法名 * @param prefix 前缀 * @param fieldName 字段名 * @return 方法名 */ private String convertName(String prefix, String fieldName){ char[] tmp = fieldName.toCharArray(); tmp[0] = (tmp[0] + "").toUpperCase().charAt(0); return prefix + new String(tmp); } /** * 将Java命名规则转换成数据库中的命名规则 * @param name Java命名 * @return 数据库命名 */ private String convertName(String name){ Matcher m = p.matcher(name); StringBuffer t = new StringBuffer(); while(m.find()){ m.appendReplacement(t, "_$1"); } m.appendTail(t); //类名一般第一个字母大写,所以会多一个'_'符号,如果有符号则需要删除掉 if(t.charAt(0) == '_'){ t.deleteCharAt(0); } return t.toString().toUpperCase().replaceAll("_+", "_"); } /** * 初始化插入语句 */ private void createInsert(){ StringBuffer insert = new StringBuffer("insert into "); StringBuffer values = new StringBuffer("values("); insert.append(this.tableName); insert.append("("); for(int i = 0; i < this.columns.length; i++){ insert.append(this.columns[i]); insert.append(", "); values.append("?, "); } insert.delete(insert.length() - 2, insert.length()); values.delete(values.length() - 2, values.length()); this.insert = insert.append(") ").append(values).append(")").toString(); log.debug(this.entityClass.getName() + " insert SQL -> " + this.insert); } /** * 初始化删除语句 */ private void createDelete(){ StringBuilder delete = new StringBuilder("delete from "); delete.append(this.tableName); delete.append(" t where t.ID = ?"); this.delete = delete.toString(); log.debug(this.entityClass.getName() + " delete SQL -> " + this.delete); } /** * 初始化更新语句 */ private void createUpdate(){ StringBuilder update = new StringBuilder("update "); update.append(this.tableName); update.append(" t set "); for(int i = 0; i < this.columns.length; i++){ if(this.columns[i].equals("ID")){ continue; } update.append("t."); update.append(this.columns[i]); update.append(" = ?, "); } update.deleteCharAt(update.length() - 2); update.append("where t.ID = ?"); this.update = update.toString(); log.debug(this.entityClass.getName() + " update SQL -> " + this.update); } /** * 创建查询语句 */ private void createSelect(){ StringBuilder select = new StringBuilder("select "); for(int i = 0; i < this.columns.length; i++){ select.append("t."); select.append(this.columns[i]); select.append(", "); } select.deleteCharAt(select.length() - 2); select.append(" from "); select.append(this.tableName); select.append(" t"); this.all = select.toString(); select.append(" where t.ID = ?"); this.select = select.toString(); log.debug(this.entityClass.getName() + " all SQL -> " + this.all); log.debug(this.entityClass.getName() + " select SQL -> " + this.select); } /** * 通过类字段名取得get方法 * @param field 字段名 * @return get方法名 */ public String getterName(String field){ return this.gettersName.get(field); } /** * 通过类字段名取得set方法名 * @param field 字段名 * @return set方法名 */ public String setterName(String field){ return this.settersName.get(field); } /** * 通过类字段名取得数据库列明 * @param field 字段名 * @return 列名 */ public String getColumn(String field){ return this.fieldMapColumn.get(field); } /** * 通过数据库列明取得类字段名 * @param column 列明 * @return 字段名 */ public String getField(String column){ return this.columnMapField.get(column); } /** * @return the tableName */ public String getTableName() { return tableName; } /** * @return the entityClass */ public Class getEntityClass() { return entityClass; } /** * @return the delete */ public String getDelete() { return delete; } /** * @return the insert */ public String getInsert() { return insert; } /** * @return the select */ public String getSelect() { return select; } /** * @return the update */ public String getUpdate() { return update; } /** * @return the columns */ public String[] getColumns() { return columns; } /** * @return the fields */ public String[] getFields() { return fields; } /** * @return the mappedColumnCount */ public Integer getMappedColumnCount() { return mappedColumnCount; } /** * @return the all */ public String getAll() { return all; } /** * @return the fieldsType */ public Class[] getFieldsType() { return fieldsType; } }
4.GenericDaoDefault:简单扩展了一下Spring的JdbcDaoSupport,统一处理了几个比较令人厌恶的琐碎代码。
public class GenericDaoDefault<E extends Entity> extends JdbcDaoSupport implements GenericDao<E> { // 泛型类型 protected Class entityClass; // 实体描述类 private EntityMapper entity; // 删除order by字句使用的正则表达式 private static Pattern removeOrderByPattern = Pattern.compile("order\\s*by[\\w|\\W|\\s|\\S]*", Pattern.CASE_INSENSITIVE); // 分页处理器 private PaginationProcessor paginationProcessor; // 主键生成器 private IDGenerator iDGenerator; /** * 构造方法 */ public GenericDaoDefault(){ try{ this.entityClass = GenericUtils.getGenericClass(this.getClass()); if(this.entityClass != null){ this.entity = new EntityMapper(this.entityClass); } }catch(Exception ex){ logger.error("初始化" + this.getClass() + "失败", ex); } } /* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#executeUpdate(java.lang.String, java.lang.Object[]) */ public int update(String ql, Object... args) { if(logger.isDebugEnabled()){ logger.debug("Update SQL: \"" + ql + "\""); } return this.getJdbcTemplate().update(ql, args); } /* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#delete(java.io.Serializable) */ public void delete(Serializable id) { this.update(this.entity.getDelete(), id); } /* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#delete(com.funstool.platform.common.dao.Entity) */ public void delete(E entity) { this.delete(entity.getId()); } /* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#get(java.io.Serializable) */ public E get(Serializable id) { try{ Connection conn = super.getConnection(); if(logger.isDebugEnabled()){ logger.debug("Select SQL: \"" + this.entity.getSelect() + "\""); } PreparedStatement ps = conn.prepareStatement(this.entity.getSelect()); ps.setObject(1, id); ResultSet rs = ps.executeQuery(); return (E)this.entity.createFromResultSet(rs); } catch(SQLException ex) { logger.warn("获取实体错误", ex); return null; } } /* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#get(java.lang.String, com.funstool.platform.common.dao.Page, java.lang.Object[]) */ public List query(String ql, Page page, Object... args) { ql = (String)this.paginationProcessor.analyse(ql, page); if(logger.isDebugEnabled()){ logger.debug("Query SQL: \"" + ql + "\""); } page.setRecord(super.getJdbcTemplate().queryForList(ql, args)); return page.getRecord(); } /* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#get(java.lang.String, java.lang.Object[]) */ public List query(String ql, Object... args) { if(logger.isDebugEnabled()){ logger.debug("Query SQL: \"" + ql + "\""); } return super.getJdbcTemplate().queryForList(ql, args); } /* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#getAll(com.funstool.platform.common.dao.Page, com.funstool.platform.common.dao.Sort[]) */ public List getAll(Page page, Sort... sorts) { String sql = null; if(sorts != null && sorts.length > 0){ StringBuilder s = new StringBuilder(this.entity.getAll()); s.append(" order by "); for(int i = 0; i < sorts.length; i++){ if(sorts[i] == null){ continue; } s.append(sorts[i].toString()); s.append(", "); } s.delete(s.length() - 2, s.length()); sql = (String)this.paginationProcessor.analyse(s.toString(), page); if(logger.isDebugEnabled()){ logger.debug("Select SQL: \"" + sql + "\""); } page.setRecord(super.getJdbcTemplate().queryForList(sql)); return page.getRecord(); } else { sql = (String)this.paginationProcessor.analyse(this.entity.getAll(), page); if(logger.isDebugEnabled()){ logger.debug("Select SQL: \"" + sql + "\""); } page.setRecord(super.getJdbcTemplate().queryForList(sql)); return page.getRecord(); } } /* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#save(java.lang.Object) */ public void save(E entity) { String[] fields = this.entity.getFields(); Object[] values = new Object[fields.length]; try{ if(entity.getId() == null){ entity.setId(iDGenerator.generate(super.getConnection())); for(int i = 0; i < fields.length; i++){ values[i] = this.entityClass.getMethod(this.entity.getterName(fields[i])).invoke(entity); } this.update(this.entity.getInsert(), values); } else { int idx = 0; for(int i = 0; i < fields.length; i++){ if(fields[i].equals("id")){ continue; } values[idx++] = this.entityClass.getMethod(this.entity.getterName(fields[i])).invoke(entity); } values[values.length - 1] = entity.getId(); this.update(this.entity.getUpdate(), values); } } catch(Exception ex) { logger.warn("保存实体错误", ex); throw new RuntimeException(ex); } } /* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#count(java.lang.String, java.lang.Object[]) */ public int count(String ql, Object... args) { String sql = "select count(*) " + removeSelect(this.removeOrderBy(ql)); if(logger.isDebugEnabled()){ logger.debug("Count SQL: \"" + sql + "\""); } return super.getJdbcTemplate().queryForInt(sql, args); } /* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#deleteBatchByEntitiesId(java.util.List) */ public void deleteBatchByEntitiesId(Object[] entitiesId) { StringBuilder str = new StringBuilder("delete from "); str.append(this.entity.getTableName()); str.append(" t where t.id in ("); for(int i = 0; i < entitiesId.length; i++){ str.append("?,"); } str.deleteCharAt(str.length() - 1); str.append(")"); this.update(str.toString(), entitiesId); } /* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#deleteBatchByEntities(com.funstool.platform.common.dao.EntityListWrapper) */ public void deleteBatchByEntities(List<E> entities) { StringBuilder str = new StringBuilder("delete from "); str.append(this.entity.getTableName()); str.append(" t where t.id in ("); for(int i = 0; i < entities.size(); i++){ str.append("?,"); } str.deleteCharAt(str.length() - 1); str.append(")"); if(!(entities instanceof EntityListWrapper)){ entities = new EntityListWrapper(entities); } this.update(str.toString(), ((EntityListWrapper)entities).getEntitiesId()); } /* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#getAll(java.lang.Integer, java.lang.Integer, com.funstool.platform.common.dao.Sort[]) */ public List getAll(Integer pageSize, Integer pageIndex, Sort... sorts) { Page page = new Page(pageSize, pageIndex, false); return this.getAll(page, sorts); } /* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#query(java.lang.String, java.lang.Integer, java.lang.Integer, java.lang.Object[]) */ public List query(String ql, Integer pageSize, Integer pageIndex, Object... args) { Page page = new Page(pageSize, pageIndex, false); return this.query(ql, page, args); } /** * 删除ql语句中的order by字句 * @param ql 查询语句 * @return 删除后的查询语句 */ private String removeOrderBy(String ql){ if(ql != null && !"".equals(ql)){ Matcher m = removeOrderByPattern.matcher(ql); StringBuffer sb = new StringBuffer(); while (m.find()) { m.appendReplacement(sb, ""); } m.appendTail(sb); return sb.toString(); } return ""; } /** * 去除ql语句中的select子句 * @param ql 查询语句 * @return 删除后的语句 */ private String removeSelect(String ql) { Assert.hasText(ql); int beginPos = ql.toLowerCase().indexOf("from"); Assert.isTrue(beginPos != -1, " sql : " + ql + " must has a keyword 'from'"); return ql.substring(beginPos); } public void setPaginationProcessor(PaginationProcessor paginationProcessor) { this.paginationProcessor = paginationProcessor; } public void setIDGenerator(IDGenerator idGen) { this.iDGenerator = idGen; } }
我用jdk1.5的,上apache下载的文件出错啊。
邮箱:380546033@qq.com
1,mapRow可以用reflect做个通用的接口
public Object mapRow(ResultSet rs,String className)
{
....
}
2,加上线程同步和final:
private final Object lock; public void update(String sql, final Object[] args, final boolean isGeneralKey) throws DaoException { synchronized (lock) { ... } }
一点拙见:
1,LZ的思路我觉得挺明确的,也比较符合大众的口味。
2,澄清下一些历史。
但是spring的依赖注入和策略模式不是很相似嘛,提出控制反转后又提出依赖注入,诸多的概念不感觉重复吗?我写代码只是想从中获得提高
IoC 的概念是Michael Mattson在1996提出来的,Martin Fowler 把IOC就称为DI设计模式,后来IoC鼻祖之一 Stefano Mazzocchi 却指出Martin Fowler这个忽悠了大家,仅仅是从字面上理解。
我觉得比较好的理解是:软件的组装部署和配置完全是由非业务逻辑模块反过来主动控制业务逻辑模块来安排。
详细的内容,见BLOG:http://c-j.iteye.com/admin/blogs/443505
而关于这点思想,从LZ的代码上来看,我感觉仅仅体现在了如下几行:
try {
CourseDAO courseDao = (CourseDAO) DaoFactory.getInstance().getDAO(
"courseDao");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
3,Spring我觉得IOC只是他的基础,这个也是很简单的东西,精髓,但Johnson不仅仅只写出了IOC,也同时提供了transaction,并保证了线程安全(据说是用ThreadLocal保证的)。
所以,至少我在LZ的代码里好像没看到保证线程安全的机制。我觉得LZ可以加进去,保证不发生死锁现象。
最后,谢谢LZ提供的DBCP的信息。
Spring的依赖注入我觉得更像静态工厂方法吧(没看过Spring源码),也是去读取配置文件...
控制反转(IoC)是一种理论,依赖注入(DI)是实现IoC的一种方式而已,并不重复...
学习学习
autoCommit 有意义吗? 通常会把connection autoCommit设置为false,等做完一段操作后 connection。commit() 这不就实现了transcation事务么
对,我说的就是这个,我说可以设置autoCommit-》setAutoCommit为true或 false,为false的话当然只能自己写事务代码了...
true的时候也可以做为readonly的transaction来处理啊。思路不错,我现在也重复发明了一个轮子。至少有什么问题,随时都可以自己改了,不用读那么多别人的代码,如果理解不透的话,改了还会影响其他地方。我觉得没有必要反对一切重复发明, 在重复发明的同时也一定是有创新的。
为什么?
难道是看到了DataAccessException?
我是主张extends Exception。
讨论下
autoCommit 有意义吗? 通常会把connection autoCommit设置为false,等做完一段操作后 connection。commit() 这不就实现了transcation事务么
对,我说的就是这个,我说可以设置autoCommit-》setAutoCommit为true或 false,为false的话当然只能自己写事务代码了...
相关推荐
DAO(Data Access Object)设计模式是软件开发中一种常见的用于处理数据访问的模式,它将业务逻辑与数据访问逻辑分离,使得代码结构更加清晰,更易于维护和测试。在Java开发中,DAO模式广泛应用于数据库操作,为应用...
DAO(Data Access Object)设计模式是一种在Java编程中常见的软件设计模式,主要目的是为了将业务逻辑与数据访问操作分离,从而提高代码的可重用性和可维护性。这个压缩包文件"DAO设计模式辅助资料"显然是为了帮助...
DAO(Data Access Object)设计模式是一种软件设计模式,它用于封装对数据库的所有访问,从而将业务逻辑和数据访问逻辑分离开来。DAO模式的核心思想是创建一个接口或抽象类,代表一个特定的数据操作,然后创建该接口...
DAO(Data Access Object)设计模式是一种在软件工程中常见的用于处理数据访问的模式,它将业务逻辑和数据访问逻辑分离,使得系统更加模块化,提高了代码的可复用性和可测试性。在这个“DAO设计模式(工厂+代理)”...
**JSP+Servlet+AJAX DAO设计模式详解** 在Web开发中,DAO(Data Access Object)设计模式是一种常用的设计模式,用于将业务逻辑与数据访问层进行解耦,提高代码的可维护性和可复用性。本篇我们将深入探讨如何在JSP...
DAO(Data Access Object)设计模式是一种在软件工程中用于封装对数据库访问的模式,它将业务逻辑和数据访问逻辑分离,提高代码的可重用性和可测试性。在这个基于DAO设计模式的新闻发布系统中,我们可以深入探讨以下...
DAO(Data Access Object)设计模式是一种在软件开发中用于封装对数据库操作的模式,它将数据访问逻辑与业务逻辑分离,使得系统更易于维护和扩展。在这个设计模式中,DAO作为数据层,提供了对数据库的一系列原子性...
### DAO设计模式详解 #### 一、概述 数据访问对象(Data Access Object,简称DAO)设计模式是一种在软件工程特别是企业级应用开发中非常常见的设计模式。它的主要目的是分离业务逻辑与数据访问逻辑,使系统架构...
DAO设计模式是Java开发中常用的一种数据访问模式,它将底层数据访问操作与上层业务逻辑相分离。这一模式的目的在于封装所有对数据源的访问,并提供抽象接口,使得业务逻辑层与数据访问层解耦,从而降低业务代码与...
DAO(Data Access Object)设计模式是Java Web开发中常用的一种设计模式,它的主要目的是将业务逻辑与数据访问操作分离,提高代码的可复用性和可维护性。在本精讲中,我们将深入探讨DAO设计模式的原理、实现方式以及...
**DAO设计模式详解** 在Web开发中,DAO(Data Access Object)设计模式是一种常见的用于分离业务逻辑层与数据访问层的架构模式。DAO的主要目的是为了提供一个统一的接口,使得业务逻辑组件可以与数据库交互而无需...
### J2EE学习笔记——DAO设计模式基础 #### 一、引言 在J2EE(Java 2 Enterprise Edition)开发中,DAO (Data Access Object) 设计模式是一种常用的数据访问层实现方式,用于分离业务逻辑与数据访问逻辑,使得程序...
JAVA+DAO 设计模式详解 在软件开发中,数据持久化是一个非常重要的步骤,特别是在WEB应用程序中。为了解决数据持久化的问题,开发者通常会采用各种设计模式,其中DAO(Data Access Object)设计模式是一个非常流行...
DAO(Data Access Object)设计模式是一种在软件工程中常见的用于处理数据访问的模式,它将业务逻辑与数据访问操作分离,使得系统更加模块化,提高了代码的可复用性和可测试性。在这个“李兴华 DAO设计模式 实现 增...
### Java DAO 设计模式 #### 一、DAO设计模式的概念 **DAO**(Data Access Object)设计模式是一种在Java EE环境中广泛使用的数据访问模式,它主要应用于处理数据存储组件的交互。这种模式的主要目的是将底层数据...
Java DAO(Data Access Object)设计模式是一种常用的软件设计模式,用于在Java应用程序中与数据库进行交互。DAO模式的主要目的是为了实现数据访问层的隔离,它将业务逻辑与数据存储细节分离开来,使得代码更加模块...
暴露给客户端的DAO接口在低层数据源的实现发生改变时并不会随着改变,所以这种设计模式使得DAO可以适应不同的数据储存方式类型而不影响客户端和商业组件.最主要的, DAO还在组件和数据源之间扮演着协调者的角色. DAO...
DAO(Data Access Object)设计模式是一种在Java编程中常见的用于处理数据访问的模式,它将业务逻辑组件与数据访问逻辑分离,提供了一种抽象层,使得应用代码与具体的数据存储方式解耦。DAO模式的核心思想是创建一个...