虽然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);
}
}
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;
}
}