`

DAO设计模式

阅读更多

      虽然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

cousrsDao=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会更能简化其中的实现。

 

分享到:
评论

相关推荐

    DAO设计模式 DAO 设计模式 JAVA设计模式

    DAO(Data Access Object)设计模式是软件开发中一种常见的用于处理数据访问的模式,它将业务逻辑与数据访问逻辑分离,使得代码结构更加...因此,深入理解并灵活运用DAO设计模式对于提升Java应用程序的质量至关重要。

    DAO设计模式DAO设计模式

    ### DAO设计模式详解 #### 一、概述 数据访问对象(Data Access Object,简称DAO)设计模式是一种在软件工程特别是企业级应用开发中非常常见的设计模式。它的主要目的是分离业务逻辑与数据访问逻辑,使系统架构...

    DAO设计模式辅助资料

    这个压缩包文件"DAO设计模式辅助资料"显然是为了帮助开发者更好地理解和应用DAO模式。下面,我们将深入探讨DAO设计模式的核心概念、实现方式以及它在实际开发中的应用。 DAO设计模式的基本思想是为数据库操作创建一...

    JSP+Servlet+AJAX的dao设计模式

    **JSP+Servlet+AJAX DAO设计模式详解** 在Web开发中,DAO(Data Access Object)设计模式是一种常用的设计模式,用于将业务逻辑与数据访问层进行解耦,提高代码的可维护性和可复用性。本篇我们将深入探讨如何在JSP...

    基于DAO设计模式的新闻发布系统

    在这个基于DAO设计模式的新闻发布系统中,我们可以深入探讨以下几个核心知识点: 1. DAO设计模式:DAO模式的核心思想是创建一个接口,该接口定义了对数据存储的通用操作,然后实现这个接口以处理具体的数据库交互。...

    DAO设计模式(工厂+代理)

    在这个“DAO设计模式(工厂+代理)”的例子中,我们将探讨如何结合工厂模式和代理模式来实现更灵活、更易于维护的DAO层。 首先,让我们理解DAO的基本概念。DAO是一个接口或抽象类,定义了对数据库进行操作的方法,...

    李兴华DAO设计模式

    在描述的课程中,李兴华先生讲解了DAO设计模式,并通过实例分析来阐述如何在业务层和服务层之间进行交互。例如,业务层可能需要实现以下功能: 1. 新雇员增加:业务层首先检查雇员编号是否已存在(调用数据层的查询...

    Dao设计模式

    DAO设计模式是Java开发中常用的一种数据访问模式,它将底层数据访问操作与上层业务逻辑相分离。这一模式的目的在于封装所有对数据源的访问,并提供抽象接口,使得业务逻辑层与数据访问层解耦,从而降低业务代码与...

    J2EE学习笔记--DAO设计模式基础.txt

    ### J2EE学习笔记——DAO设计模式基础 #### 一、引言 在J2EE(Java 2 Enterprise Edition)开发中,DAO (Data Access Object) 设计模式是一种常用的数据访问层实现方式,用于分离业务逻辑与数据访问逻辑,使得程序...

    李兴华 DAO设计模式 实现 增删改查 分页查询 完整代码

    在这个“李兴华 DAO设计模式 实现 增删改查 分页查询 完整代码”项目中,我们将探讨DAO模式如何应用于实现数据库的CRUD(创建、读取、更新、删除)操作以及分页查询。 1. DAO设计模式基础: DAO设计模式的核心是...

    DAO设计模式精讲(java web开发)

    在本精讲中,我们将深入探讨DAO设计模式的原理、实现方式以及在实际项目中的应用。 **DAO设计模式的核心思想** DAO设计模式的核心是创建一个接口,该接口定义了对数据库进行操作的方法,如查询、插入、更新和删除...

    Dao设计模式教程

    在本教程中,我们将深入探讨DAO设计模式的各个方面,包括其概念、优点、结构以及如何在实际项目中应用。 1. **DAO设计模式的概念** DAO设计模式是一种面向对象的设计模式,用于处理应用程序和数据存储之间的交互。...

    WEB开发经典之 DAO设计模式

    **DAO设计模式详解** 在Web开发中,DAO(Data Access Object)设计模式是一种常见的用于分离业务逻辑层与数据访问层的架构模式。DAO的主要目的是为了提供一个统一的接口,使得业务逻辑组件可以与数据库交互而无需...

    初步认识JAVA DAO设计模式

    总结来说,DAO设计模式在Java开发中扮演着重要的角色,尤其是在处理数据持久化问题时,它提供了一种灵活且可扩展的方式来管理数据访问,降低了系统的复杂性,提高了代码的可维护性。通过将数据访问逻辑封装在DAO中,...

    Java DAO 设计模式.pdf

    #### 一、DAO设计模式的概念 **DAO**(Data Access Object)设计模式是一种在Java EE环境中广泛使用的数据访问模式,它主要应用于处理数据存储组件的交互。这种模式的主要目的是将底层数据访问操作与业务逻辑分开,...

    初步认识JAVA+DAO设计模式.pdf

    本文将详细讲解JAVA+DAO设计模式的概念、原理和实现。 DAO 设计模式背景 在软件开发中,数据持久化是一个非常重要的步骤。不同的数据源会有不同的访问机制和API,这使得程序的开发和维护变得非常复杂。例如,在...

    JavaEE技术-DAO设计模式

    DAO设计模式是JavaEE中用于数据层操作的一种模式,其核心目的是简化代码编写、提高可移植性,以及实现更好的代码维护和可读性。在没有使用DAO设计模式之前,数据库操作通常直接在JSP页面中使用JDBC代码,或者通过...

Global site tag (gtag.js) - Google Analytics