- 虽然DAO模式已经有了好多的成熟的框架,但它仍然是一个比较重要的设计模式。要做一个比较合理的DAO模式,你需要对工厂模式、单例模式、模板模式、策略模式、代理模式、泛型、反射机制、输入输出、异常等知识比较熟悉。下面结合自己理解,设计一个DAO设计模式的例子,希望大家给与指正。
- 1、数据库连接池的工具类。
- 在数据库连接池的工具类中,采用了开源的DBCP数据库连接池,调用了DataSource接口,DBCP中关于Datasource的Connection采用了动态代理的方式实现,在这里只是提出,感兴趣可以查看其源码,该工具类采用可配置的方式实现的,代码如下:
- Java代码
- 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();
- }
- }
- }
- }
- }
- 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
- Java代码
- #连接设置
- 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
- #连接设置
- 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层的必要异常都抛出。
- Java代码
- 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);
- }
- }
- 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类
- Java代码
- 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;
- }
- }
- 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层的操作能和业务层解耦。
- Java代码
- 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;
- }
- 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层的常用操作类进行提取。
- Java代码
- 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);
- }
- }
- }
- }
- 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通用操作类中定义接口,用于对象的转化。
- Java代码
- 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;
- }
- 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操作的实现类中,我们采用了策略模式。
- Java代码
- 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;
- }
- }
- }
- 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、我们定义工厂类,在定义工厂类,考虑到通用性,我们采用了反射机制加配置文件的形式来实现的。同时,在工厂模式中引入了饿汉式单例模式。
- Java代码
- /**
- *
- */
- 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());
- }
- }
- /**
- *
- */
- 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
- Java代码
- courseDao=com.cvicse.dao.impl.CourseDAOImpl
- entsDao=com.cvicse.dao.impl.StudentDAOImpl
- courseDao=com.cvicse.dao.impl.CourseDAOImpl
- studentsDao=com.cvicse.dao.impl.StudentDAOImpl 8、业务层的调用方式,这里用客户端方式模拟的。在业务层通过接口的方式调用,使得DAO层和业务层能够解耦。
- Java代码
- 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();
- }
- }
- }
- 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会更能简化其中的实现。
虽然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();
- }
- }
- }
- }
- }
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
#连接设置 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);
- }
- }
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;
- }
- }
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;
- }
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);
- }
- }
- }
- }
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;
- }
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;
- }
- }
- }
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());
- }
- }
/** * */ 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
- entsDao=com.cvicse.dao.impl.StudentDAOImpl
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();
- }
- }
- }
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会更能简化其中的实现。