Hướng dẫn Java Design Pattern – DAO

Một trong những khía cạnh quan trọng của lớp nghiệp vụ (business layer) là lớp truy cập dữ liệu (data access layer) để kết nối các dịch vụ (service) với cơ sở dữ liệu (database). Việc truy cập dữ liệu tùy thuộc vào nguồn dữ liệu, loại lưu trữ như database, text file, xml file, json file, …Thậm chí nó khác với cách triển khai của nó, ví dụ: cú pháp truy vấn SQL khác nhau giữa MySQL, SQL Server, Oracle, … Với mong muốn sẽ không có gì khác biệt khi truy cập cơ sở dữ liệu quan hệ, phân tích xml file hay bất kỳ nguồn dữ liệu nào khác, chúng ta có thể áp dụng mẫu thiết kế đối tượng truy cập dữ liệu (Data Access Object Pattern– DAO Pattern).

1. DAO Pattern là gì?

Data Access Object (DAO) Pattern là một trong những Pattern thuộc nhóm cấu trúc (Structural Pattern).  Mẫu thiết kế DAO được sử dụng để phân tách logic lưu trữ dữ liệu trong một lớp riêng biệt. Theo cách này, các service được che dấu về cách các hoạt động cấp thấp để truy cập cơ sở dữ liệu được thực hiện. Nó còn được gọi là nguyên tắc Tách logic (Separation of Logic).

Ý tưởng là thay vì có logic giao tiếp trực tiếp với cơ sở dữ liệu, hệ thống file, dịch vụ web hoặc bất kỳ cơ chế lưu trữ nào mà ứng dụng cần sử dụng, chúng ta sẽ để logic này sẽ giao tiếp với lớp trung gian DAO. Lớp DAO này sau đó giao tiếp với hệ thống lưu trữ, hệ quản trị CSDL như thực hiện các công việc liên quan đến lưu trữ và truy vấn dữ liệu (tìm kiếm, thêm, xóa, sửa,…).

DAO Pattern dựa trên các nguyên tắc thiết kế abstraction và encapsulation. Nó bảo vệ phần còn lại của ứng dụng khỏi mọi thay đổi trong lớp lưu trữ, ví dụ: thay đổi database từ Oracle sang MySQL, thay đổi công nghệ lưu trữ từ file sang database.

Trong Java, DAO được triển khai theo nhiều cách khác nhau như Java Persistence API,  Enterprise Java Bean (EJP), Object-relational mapping (ORM) với các implement cụ thể như Hibernate, iBATIS, Spring JPA, … Chi tiết về các phần này chúng ta sẽ cùng thảo luận ở một bài viết khác.

2. Cài đặt DAO Pattern như thế nào?

Các thành phần tham gia mẫu Data Access Object (DAO) Pattern:

  • BusinessObject : đại diện cho Client, yêu cầu truy cập vào nguồn dữ liệu để lấy và lưu trữ dữ liệu.
  • DataAccessObject (DAO): là một interface định nghĩa các phương thức trừu tượng việc triển khai truy cập dữ liệu cơ bản cho BusinessObject để cho phép truy cập vào nguồn dữ liệu (DataSource).
  • DataAccessObjectConcrete : cài đặt các phương thức được định nghĩa trong DAO, lớp này sẽ thao tác trực tiếp với nguồn dữ liệu (DataSource).
  • DataSource : là nơi chứa dữ liệu, nó có thể là database, xml, json, text file, webservice, …
  • TransferObject : là một POJO (Plain old Java object) object, chứa các phương thức get/set được sử dụng để lưu trữ dữ liệu và được sử dụng trong DAO class.

2.1. Ví dụ sử dụng DAO Pattern

Ví dụ bên dưới cho chúng ta thấy cách áp dụng DAO Pattern trong việc cung cấp interface chung để thao tác với cơ sở dữ liệu (CRUD). Các thao tác này bao gồm: Create/ Save, Read/ Get, Update, Delete.

User.java

package com.maixuanviet.patterns.structural.dao;
 
import lombok.AllArgsConstructor;
import lombok.Data;
 
@Data
@AllArgsConstructor
public class User {
     
    private int id;
     
    private String name;
     
    private String email;
}

Dao.java

package com.maixuanviet.patterns.structural.dao;
 
import java.util.List;
import java.util.Optional;
 
public interface Dao<T> {
 
    List<T> getAll();
 
    Optional<T> get(int id);
 
    void save(T t);
 
    void update(T t);
 
    void delete(T t);
}

UserDao.java

package com.maixuanviet.patterns.structural.dao;
 
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
 
public class UserDao implements Dao<User> {
 
    private List<User> users = new ArrayList<>();
 
    public UserDao() {
        users.add(new User(1, "MXV", "contact@maixuanviet.com"));
        users.add(new User(2, "VietMX", "maixuanviet.com@gmail.com"));
    }
 
    @Override
    public List<User> getAll() {
        return users;
    }
 
    @Override
    public Optional<User> get(int id) {
        return users.stream().filter(u -> u.getId() == id).findFirst();
    }
 
    @Override
    public void save(User user) {
        users.add(user);
    }
 
    @Override
    public void update(User user) {
        get(user.getId()).ifPresent(existUser -> {
            existUser.setName(user.getName());
            existUser.setEmail(user.getEmail());
        });
    }
 
    @Override
    public void delete(User user) {
        get(user.getId()).ifPresent(existUser -> users.remove(existUser));
    }
}

DaoPatternExample.java

package com.maixuanviet.patterns.structural.dao;
 
public class DaoPatternExample {
 
    private static Dao<User> userDao;
 
    public static void main(String[] args) {
        userDao = new UserDao();
 
        User user1 = userDao.get(1).get();
        System.out.println("user1: " + user1);
         
        user1.setName("updated." + user1.getName());
        userDao.update(user1);
         
        System.out.println("All users: ");
        userDao.getAll().forEach(user -> System.out.println(user));
    }
}

User.java

user1: User(id=1, name=MXV, email=contact@maixuanviet.com)
All users: 
User(id=1, name=updated. MXV, email=contact@maixuanviet.com)
User(id=2, name=VietMX, email=maixuanviet.com@gmail.com)

3. Lợi ích của DAO Pattern là gì?

  • Giảm sự kết nối (loose coupling) giữa logic nghiệp vụ (Business) và logic lưu trữ (Persistence).
  • Mẫu DAO cho phép đóng gói code để thực hiện thao tác CRUD, ngăn chặn việc implement riêng lẻ trong từng phần khác nhau của ứng dụng.
  • Dễ mở rộng, bảo trì: tất cả các chi tiết lưu trữ được ẩn khỏi phần còn lại của ứng dụng. Do đó, những thay đổi có thể được thực hiện bằng cách chỉ sửa đổi một implement của DAO trong khi phần còn lại của ứng dụng không bị ảnh hưởng. DAO hoạt động như một trung gian giữa ứng dụng và cơ sở dữ liệu.
  • Dễ hiểu: mọi người đều theo một quy chuẩn đã được định sẵn, nên dễ hiểu hơn, tiết kiệm được nhiều thời gian hơn.
  • Trong một dự án lớn hơn, các nhóm khác nhau làm việc trên các phần khác nhau của ứng dụng, mẫu DAO cho phép phân tách rõ ràng các thành phần này.

4. Sử dụng DAO Pattern khi nào?

  • Khi muốn thay đổi nguồn dữ liệu sau này, như chuyển từ cơ dữ liệu MySQL sang Oracle, SQL Server, …
  • Khi muốn phân tách rõ ràng các thành phần của ứng dụng.

Related posts:

Spring Security 5 – OAuth2 Login
Introduction to the Java NIO2 File API
Java Program to Implement Stein GCD Algorithm
Java Program to Implement HashMap API
Understanding Memory Leaks in Java
Câu lệnh điều khiển vòng lặp trong Java (break, continue)
Spring Security – security none, filters none, access permitAll
Java Program to Represent Graph Using Adjacency Matrix
Simple Single Sign-On with Spring Security OAuth2
Java program to Implement Tree Set
Java Program to Implement Flood Fill Algorithm
Loại bỏ các phần tử trùng trong một ArrayList như thế nào trong Java 8?
Circular Dependencies in Spring
Java Program to Perform Optimal Paranthesization Using Dynamic Programming
Java Program to Show the Duality Transformation of Line and Point
Java Program to Represent Graph Using Adjacency List
Jackson – Unmarshall to Collection/Array
Java Program to Find Shortest Path Between All Vertices Using Floyd-Warshall’s Algorithm
Send email with JavaMail
Java Program to Check whether Graph is Biconnected
Java Program to Implement Sorted Circularly Singly Linked List
A Guide to JUnit 5 Extensions
Java Program to Implement Fermat Factorization Algorithm
Tránh lỗi ConcurrentModificationException trong Java như thế nào?
Java Program to Compute DFT Coefficients Directly
Java Program to Implement Sieve Of Sundaram
Java Program to Implement EnumMap API
Mix plain text and HTML content in a mail
Java Program to Implement the String Search Algorithm for Short Text Sizes
Java Program to Perform Polygon Containment Test
Disable DNS caching
Hướng dẫn Java Design Pattern – Command