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");
}
}