读书人

dao 设计方式

发布时间: 2012-08-15 16:57:16 作者: rapoo

dao 设计模式

虽然DAO模式已经有了好多的成熟的框架,但它仍然是一个比较重要的设计模式。要做一个比较合理的DAO模式,你需要对工厂模式、单例模式、模板模式、策略模式、代理模式、泛型、反射机制、输入输出、异常等知识比较熟悉。下面结合自己理解,设计一个DAO设计模式的例子,希望大家给与指正。

1、数据库连接池的工具类。

???? 在数据库连接池的工具类中,采用了开源的DBCP数据库连接池,调用了DataSource接口,DBCP中关于Datasource的Connection采用了动态代理的方式实现,在这里只是提出,感兴趣可以查看其源码,该工具类采用可配置的方式实现的,代码如下:

?

?dao 设计方式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

?dao 设计方式#连接设置driverClassName=com.mysql.jdbc.Driverurl=jdbc:mysql://localhost:3306/test123username=rootpassword=#<!-- 初始化连接 -->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, SERIALIZABLEdefaultTransactionIsolation=READ_UNCOMMITTED

?2、异常定义,用于处理DAO层的异常类,因为异常最好要在业务层进行处理,个人认为这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类

?dao 设计方式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层的操作能和业务层解耦。

?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层的常用操作类进行提取。

?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通用操作类中定义接口,用于对象的转化。

?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操作的实现类中,我们采用了策略模式。

?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 stubString 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 stubString 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 stubString 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 stubString 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 stubString 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 stubString 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、我们定义工厂类,在定义工厂类,考虑到通用性,我们采用了反射机制加配置文件的形式来实现的。同时,在工厂模式中引入了饿汉式单例模式。

?dao 设计方式/** * */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

?dao 设计方式cousrsDao=com.cvicse.dao.impl.CourseDAOImplstudentsDao=com.cvicse.dao.impl.StudentDAOImpl

?8、业务层的调用方式,这里用客户端方式模拟的。在业务层通过接口的方式调用,使得DAO层和业务层能够解耦。

?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 stubtry {CourseDAO courseDao = (CourseDAO) DaoFactory.getInstance().getDAO("courseDao");} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}

?

总结:在这个DAO设计模式中,涉及到很多java的基础知识,同时,也涉及太多的模式。只有灵活应用,才能体会的其中的灵活。关于DAO具体实现可以采用spring的simpetempate会更能简化其中的实现。

读书人网 >软件开发

热点推荐