DAO模式
掌握DAO模式
DAO (DataAccessobjects 数据存取对象)是指位于业务逻辑和持久化数据之间实现对持久化数据的访问。通俗来讲,就是将数据库操作都封装起来。
对外提供相应的接口
在面向对象设计过程中,有一些"套路”用于解决特定问题称为模式。
DAO 模式提供了访问关系型数据库系统所需操作的接口,将数据访问和业务逻辑分离对上层提供面向对象的数据访问接口。
从以上 DAO 模式使用可以看出,DAO 模式的优势就在于它实现了两次隔离。
- 隔离了数据访问代码和业务逻辑代码。业务逻辑代码直接调用DAO方法即可,完全感觉不到数据库表的存在。分工明确,数据访问层代码变化不影响业务逻辑代码,这符合单一职能原则,降低了藕合性,提高了可复用性。
- 隔离了不同数据库实现。采用面向接口编程,如果底层数据库变化,如由 MySQL 变成 Oracle 只要增加 DAO 接口的新实现类即可,原有 MySQ 实现不用修改。这符合 "开-闭" 原则。该原则降低了代码的藕合性,提高了代码扩展性和系统的可移植性。
一个典型的DAO 模式主要由以下几部分组成。
- 1、DAO接口: 把对数据库的所有操作定义成抽象方法,可以提供多种实现。
- 2、DAO 实现类: 针对不同数据库给出DAO接口定义方法的具体实现。
- 3、实体类:用于存放与传输对象数据。
- 4、数据库连接和关闭工具类: 避免了数据库连接和关闭代码的重复使用,方便修改。
实例:
测试类:
//测试类
public class Test {
public static void main(String[] args) {
Emp e = new Emp(9950,"HELLO","CLERK",5050.0F,300,null,new Date(),20);
EmpDao dao = new EmpDaoImpl();
//添加
// int count = dao.saveEmp(e);
// System.out.println(count);
//查找
// Emp e2 = dao.selectEmp(7369);
// System.out.println(e2.toString());
//删除
// int count = dao.deleteEmp(9950);
// System.out.println(count);
//替换
// int count = dao.updateEmp(e,4545);
// System.out.println(count);
// 查询所有员工
// List<Emp> e3 = dao.selectAllEmp();
// for (Emp e4: e3) {
// System.out.println(e4.toString());
// }
//根据入职时间查找员工
// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// Date d1 =null;
// Date d2 =null;
//
// try {
// d1 = sdf.parse("1980-01-01");
// d2 = sdf.parse("1990-01-01");
// } catch (ParseException ex) {
// ex.printStackTrace();
// }
// List<Emp>e7 = dao.TimeEmp(d1,d2);
// for (Emp e8: e7) {
// System.out.println(e8.toString());
// }
//模糊查询
// List<Emp> e5 = dao.vagueSelectEmp("%A%");
// for (Emp e6: e5) {
// System.out.println(e6.toString());
// }
}
}
实体类:
package mysqltest.pojo;
import java.util.Date;
public class Emp {
private Integer empno;
private String ename;
private String job;
private Float Sal;
private Integer comm;
private Integer mgr;
private Date hiredate;
private int deptno;
public Integer getEmpno() {
return empno;
}
public void setEmpno(Integer empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public Float getSal() {
return Sal;
}
public void setSal(Float sal) {
Sal = sal;
}
public Integer getComm() {
return comm;
}
public void setComm(Integer comm) {
this.comm = comm;
}
public Integer getMgr() {
return mgr;
}
public void setMgr(Integer mgr) {
this.mgr = mgr;
}
public Date getHiredate() {
return hiredate;
}
public void setHiredate(Date hiredate) {
this.hiredate = hiredate;
}
public int getDeptno() {
return deptno;
}
public void setDeptno(int deptno) {
this.deptno = deptno;
}
@Override
public String toString() {
return "Emp{" +
"empno=" + empno +
", ename='" + ename + '\'' +
", job='" + job + '\'' +
", Sal=" + Sal +
", comm=" + comm +
", mgr=" + mgr +
", hiredate=" + hiredate +
", deptno=" + deptno +
'}';
}
public Emp(Integer empno, String ename, String job, Float sal, Integer comm, Integer mgr, Date hiredate, int deptno) {
this.empno = empno;
this.ename = ename;
this.job = job;
Sal = sal;
this.comm = comm;
this.mgr = mgr;
this.hiredate = hiredate;
this.deptno = deptno;
}
public Emp() {
}
}
DAO接口:
package mysqltest.dao;
import mysqltest.pojo.Emp;
import java.util.Date;
import java.util.List;
public interface EmpDao {
//添加
public int saveEmp(Emp e);
//删除
public int deleteEmp(int empno);
//更新
public int updateEmp(Emp e,int empno);
//查找
public Emp selectEmp(int empno);
//返回所有值
public List<Emp> selectAllEmp();
//模糊查找
public List<Emp> vagueSelectEmp(String str);
//根据入职时间区间查找
public List<Emp> TimeEmp(Date d1,Date d2);
}
数据库连接和关闭工具类和额外的功能块(有部分冗余):
package mysqltest.dao.impl;
import mysqltest.pojo.Emp;
import java.io.IOException;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
public class BaseDao {
private static String driver;
private static String url;
private static String user;
private static String password;
//注册驱动
static {
Properties p = new Properties();
try {
p.load(BaseDao.class.getClassLoader().getResourceAsStream("mysqltest/jdbc.properties"));
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("配置文件加载异常");
}
driver = p.getProperty("DRIVER");
url = p.getProperty("URL");
user = p.getProperty("USER");
password = p.getProperty("PASSWORD");
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new RuntimeException("注册驱动异常");
}
}
//连接数据库
public static Connection getConnection(){
try {
return DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("连接数据库异常");
}
}
//关闭数据库连接
public static void closeAll(Connection conn, Statement stmt, ResultSet rs){
if(rs!=null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("ResultSet关闭异常");
}
}
if(stmt!=null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("Statement关闭异常");
}
}
if(conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("Connection关闭异常");
}
}
}
//executeUpdate执行SQL并返回一个int值(受影响的行数)
public int executeUpdate(String sql,Object... programs){
Connection con = null;
PreparedStatement preparedStatement= null;
Integer count;
try{
//初始化
con=getConnection();
preparedStatement = con.prepareStatement(sql);
//给preparedStatement设置参数
for(int i = 0;i < programs.length;i++){
preparedStatement.setObject(i+1,programs[i]);
}
//返回count
count = preparedStatement.executeUpdate();
return count;
} catch (SQLException throwables) {
throwables.printStackTrace();
throw new RuntimeException("statement异常");
} finally {
closeAll(con,preparedStatement,null);
}
}
//executeQuery执行SQL并返回一个Emp对象
public Emp executeQuery(String sql, int deptno){
Connection con = null;
PreparedStatement preparedStatement= null;
ResultSet resultSet = null;
Emp emp = new Emp();
try{
//初始化
con = getConnection();
preparedStatement = con.prepareStatement(sql);
//给preparedStatement设置参数
preparedStatement.setInt(1,deptno);
resultSet = preparedStatement.executeQuery();
//遍历结果集赋值
if (resultSet.next()){
emp.setEmpno(resultSet.getInt(1));
emp.setEname(resultSet.getString(2));
emp.setJob(resultSet.getString(3));
emp.setSal(resultSet.getFloat(4));
emp.setComm(resultSet.getInt(5));
emp.setMgr(resultSet.getInt(6));
emp.setHiredate(resultSet.getDate(7));
emp.setDeptno(resultSet.getInt(8));
}
return emp;
} catch (SQLException throwables) {
throwables.printStackTrace();
throw new RuntimeException("statement异常");
} finally {
closeAll(con,preparedStatement,null);
}
}
//executeQuery执行SQL并返回一个Emp的List集合
public List<Emp> executeQuery(String sql){
Connection con = null;
PreparedStatement preparedStatement= null;
ResultSet resultSet = null;
List<Emp> e = new ArrayList<>();
try{
//初始化
con = getConnection();
preparedStatement = con.prepareStatement(sql);
resultSet = preparedStatement.executeQuery();
//遍历结果集赋值
while(resultSet.next()){
Emp emp = new Emp();
emp.setEmpno(resultSet.getInt(1));
emp.setEname(resultSet.getString(2));
emp.setJob(resultSet.getString(3));
emp.setSal(resultSet.getFloat(4));
emp.setComm(resultSet.getInt(5));
emp.setMgr(resultSet.getInt(6));
emp.setHiredate(resultSet.getDate(7));
emp.setDeptno(resultSet.getInt(8));
e.add(emp);
}
return e;
} catch (SQLException throwables) {
throwables.printStackTrace();
throw new RuntimeException("statement异常");
} finally {
closeAll(con,preparedStatement,null);
}
}
//模糊查询 返回List<Emp>集合
public List<Emp> executeQuery(String sql,Object...programs){
Connection con = null;
PreparedStatement preparedStatement= null;
ResultSet resultSet = null;
List<Emp> e = new ArrayList<>();
try{
//初始化
con = getConnection();
preparedStatement = con.prepareStatement(sql);
//给preparedStatement设置参数
for (int i = 0; i < programs.length; i++) {
preparedStatement.setObject(i+1, programs[i]);
}
resultSet = preparedStatement.executeQuery();
//遍历结果集赋值
while(resultSet.next()){
Emp emp = new Emp();
emp.setEmpno(resultSet.getInt(1));
emp.setEname(resultSet.getString(2));
emp.setJob(resultSet.getString(3));
emp.setSal(resultSet.getFloat(4));
emp.setComm(resultSet.getInt(5));
emp.setMgr(resultSet.getInt(6));
emp.setHiredate(resultSet.getDate(7));
emp.setDeptno(resultSet.getInt(8));
e.add(emp);
}
return e;
} catch (SQLException throwables) {
throwables.printStackTrace();
throw new RuntimeException("statement异常");
} finally {
closeAll(con,preparedStatement,null);
}
}
}
实现类
package mysqltest.dao.impl;
import mysqltest.dao.EmpDao;
import mysqltest.pojo.Emp;
import java.util.Date;
import java.util.List;
public class EmpDaoImpl extends BaseDao implements EmpDao {
@Override
public int saveEmp(Emp e) {
String sql ="INSERT INTO emp VALUES (?,?,?,?,?,?,?,?)";
return super.executeUpdate(sql,e.getEmpno(),e.getEname(),e.getJob(),e.getSal(),e.getComm(),e.getMgr(),e.getHiredate(),e.getDeptno());
}
@Override
public int deleteEmp(int empno) {
String sql ="DELETE FROM emp WHERE empno = ?";
return super.executeUpdate(sql,empno);
}
@Override
public int updateEmp(Emp e,int empno) {
String sql = "UPDATE emp SET empno = ?,ename = ?,job = ?,Sal = ?,comm=?,mgr=?,hiredate=?,deptno=? WHERE empno = ?";
return super.executeUpdate(sql,e.getEmpno(),e.getEname(),e.getJob(),e.getSal(),e.getComm(),e.getMgr(),e.getHiredate(),e.getDeptno(),empno);
}
@Override
public Emp selectEmp(int empno) {
String sql = "SELECT * FROM emp WHERE empno = ?";
return super.executeQuery(sql,empno);
}
@Override
public List<Emp> selectAllEmp() {
String sql = "SELECT * FROM emp ";
return super.executeQuery(sql);
}
@Override
public List<Emp> vagueSelectEmp(String str) {
String sql = "SELECT * FROM emp WHERE ename like ?";
return super.executeQuery(sql,str);
}
@Override
public List<Emp> TimeEmp(Date d1, Date d2) {
String sql ="SELECT * FROM emp WHERE hiredate BETWEEN ? AND ?";
return super.executeQuery(sql,d1,d2);
}
}
Properties配置
开发中获得连接的四个参数(驱动,URL,用户名,密码)通常都存在配置文件中,方便后期维护,程序如果需要更换数据库,只需要修改配置文件即可。
通常情况下,我们习惯使用properties文件,此文件要求:
-
文件位置:任意,建议src下(非web应用)、classpath(web应用)
-
文件名:任意,扩展名为properties
-
文件内容:一行一组数据,格式“key=value”(不要有空格)
-
key名自定义,如果是多个单词,习惯使用点分隔,例如:jdbc.driver
-
Value值不支持中文,如果需要使用非英文字符,讲进行Unicode转换。
-
1.创建配置文件
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/student
user=root
password=root
2.加载配置文件:ResourceBundle对象
public class TextBundle {
public static String driver;
public static String url;
public static String user;
public static String password;
static {
ResourceBundle bundle = ResourceBundle.getBundle("db");
driver = bundle.getString("driver");
url = bundle.getString("url");
user = bundle.getString("user");
password = bundle.getString("password");
}
}
3.加载配置文件:Properties对象
public class TextBundle {
public static String driver;
public static String url;
public static String user;
public static String password;
static {
//1、通过当前类获取类加载器
ClassLoader classloader = TextBundle.class.getClassLoader();
//2、通过类加载器的方法获得一个输入流
InputStream is = classloader.getResourceAsStream("db.properties");
//3、创建一个properties对象
Properties props = new Properties();
//4、加载输入流
try {
props.load(is);//可以把步骤2和这个写在一起
} catch (IOException e) {
e.printStackTrace();
}
//5、获得参数值
driver = props.getProperty("driver");
url = props.getProperty("url");
user = props.getProperty("user");
password = props.getProperty("password");
}
}