2010-10-07 41 views
61

Tôi đang thiết kế một ứng dụng mới dựa trên JPA/Hibernate, Spring và Wicket. Sự khác biệt giữa các lớp DAO và Service không rõ ràng với tôi. Theo Wikipedia, DAO làLớp DAO và Dịch vụ (JPA/Hibernate + Spring)

một đối tượng cung cấp một giao diện trừu tượng đối với một số loại cơ sở dữ liệu hoặc cơ chế kiên trì, cung cấp một số hoạt động cụ thể mà không lộ chi tiết về cơ sở dữ liệu.

Tôi đã tự hỏi liệu một DAO có thể chứa các phương thức không thực sự phải làm nhiều với việc truy cập dữ liệu, nhưng thực hiện dễ dàng hơn bằng truy vấn? Ví dụ: "lấy danh sách tất cả các hãng hàng không hoạt động trên một số sân bay nhất định"? Nghe có vẻ như tôi có nhiều phương pháp lớp dịch vụ hơn, nhưng tôi không chắc liệu sử dụng JPA EntityManager trong lớp dịch vụ có phải là một ví dụ về thực hành tốt hay không?

Trả lời

51

A DAO sẽ cấp quyền truy cập vào một nguồn dữ liệu liên quan và tùy thuộc vào mức độ phức tạp của mô hình kinh doanh của bạn, trả về các đối tượng Kinh doanh chính thức hoặc đối tượng Dữ liệu đơn giản. Dù bằng cách nào, các phương pháp DAO nên phản ánh cơ sở dữ liệu hơi chặt chẽ.

Dịch vụ có thể cung cấp giao diện cấp cao hơn để không chỉ xử lý các đối tượng kinh doanh của bạn mà còn để có quyền truy cập vào chúng ngay từ đầu. Nếu tôi nhận được một đối tượng kinh doanh từ một Dịch vụ, đối tượng đó có thể được tạo từ các cơ sở dữ liệu khác nhau (và các DAO khác nhau), nó có thể được trang trí bằng thông tin được tạo từ một yêu cầu HTTP. Nó có thể có logic kinh doanh nhất định chuyển đổi một số đối tượng dữ liệu thành một đối tượng kinh doanh đơn lẻ, mạnh mẽ.Tôi thường tạo ra một DAO nghĩ rằng nó sẽ được sử dụng bởi bất cứ ai sẽ sử dụng cơ sở dữ liệu đó, hoặc tập hợp dữ liệu liên quan đến kinh doanh, nó thực sự là mã mức thấp nhất bên cạnh các trigger, chức năng và các thủ tục lưu trữ bên trong cơ sở dữ liệu.

Câu trả lời cho câu hỏi cụ thể:

tôi đã tự hỏi liệu một DAO thể chứa phương pháp mà không thực sự có làm nhiều với truy cập dữ liệu, nhưng là cách dễ dàng hơn thực hiện bằng cách sử dụng truy vấn ?

đối với hầu hết các trường hợp không, bạn sẽ muốn logic kinh doanh phức tạp hơn trong lớp dịch vụ, lắp ráp dữ liệu từ các truy vấn riêng biệt. Tuy nhiên, nếu bạn lo ngại về tốc độ xử lý, một lớp dịch vụ có thể ủy thác một hành động cho DAO mặc dù nó phá vỡ vẻ đẹp của mô hình, theo cùng cách mà một lập trình viên C++ có thể viết mã trình lắp ráp để tăng tốc các hành động nhất định.

Nghe có vẻ với tôi để được nhiều hơn một phương pháp lớp dịch vụ, nhưng tôi không chắc chắn nếu sử dụng JPA EntityManager trong lớp dịch vụ là một ví dụ về thực hành tốt ?

Nếu bạn định sử dụng người quản lý thực thể trong dịch vụ của mình, hãy nghĩ về người quản lý thực thể làm DAO của bạn, vì đó là chính xác nó là gì. Nếu bạn cần loại bỏ một số tòa nhà truy vấn dư thừa, đừng làm như vậy trong lớp dịch vụ của bạn, giải nén nó vào một lớp mà sử dụng trình quản lý thực thể và làm cho DAO của bạn. Nếu trường hợp sử dụng của bạn thực sự đơn giản, bạn có thể bỏ qua lớp dịch vụ hoàn toàn và sử dụng trình quản lý tổ chức của bạn hoặc DAO trong bộ điều khiển vì tất cả dịch vụ của bạn sẽ thực hiện là chuyển các cuộc gọi tới getAirplaneById() tới số findAirplaneById()

CẬP NHẬT - làm rõ đối với các cuộc thảo luận dưới đây, bằng cách sử dụng một người quản lý thực thể trong một dịch vụ có thể không phải là quyết định tốt nhất trong hầu hết các tình huống mà cũng có một lớp DAO vì nhiều lý do được nêu trong các ý kiến. Nhưng theo ý kiến ​​của tôi nó sẽ được trao hoàn toàn hợp lý:

  1. Dịch vụ này cần phải tương tác với bộ dữ liệu khác nhau
  2. Ít nhất một tập hợp các dữ liệu đã có một DAO
  3. lớp
  4. Dịch vụ này nằm trong một mô-đun yêu cầu một số sự kiên trì đủ đơn giản để không đảm bảo đó là DAO

ví dụ sau.

//some system that contains all our customers information 
class PersonDao { 
    findPersonBySSN(long ssn) 
} 

//some other system where we store pets 
class PetDao { 
    findPetsByAreaCode() 
    findCatByFullName() 
} 

//some web portal your building has this service 
class OurPortalPetLostAndFoundService { 

    notifyOfLocalLostPets(Person p) { 
     Location l = ourPortalEntityManager.findSingle(PortalUser.class, p.getSSN()) 
     .getOptions().getLocation(); 
     ... use other DAO's to get contact information and pets... 
    } 
} 
+1

cảm ơn câu trả lời chi tiết như vậy. tôi chỉ cần tự hỏi: nó sẽ là ok cho cả hai có một bộ sưu tập của DAO và sử dụng EntityManager trong lớp dịch vụ? –

+0

Tôi không nghĩ rằng có bất cứ điều gì sai trái với điều này, hãy nhớ những gì Bohzo nói về lớp dịch vụ là kiên trì thuyết phục. Nếu mọi thứ trở nên nhỏ hơn tầm thường, tôi chỉ có một DAO duy nhất sử dụng trình quản lý thực thể và giao dịch với tất cả các thực thể. Tôi đã không bao giờ tìm thấy bất kỳ sử dụng cho các mô hình phổ biến mà một DAO là cụ thể cho một thực thể hoặc một bảng, tôi nghĩ rằng một DAO nên được ràng buộc với một cơ sở dữ liệu, nếu lớp trở nên lớn, refactor khi nó rõ ràng những gì là dư thừa – walnutmon

+0

ok. Tôi đã hầu như nhìn thấy DAO đã được kết hợp chặt chẽ với một thực thể duy nhất/bảng và suy nghĩ uncoupling sẽ là một hành vi vi phạm thực hành tốt. vì vậy phương thức getAirlinesOperatingFrom() trong câu trả lời của Qwerky là tốt? –

0

Dao là đối tượng truy cập dữ liệu. Nó lưu trữ/cập nhật/lựa chọn các thực thể trên cơ sở dữ liệu. Đối tượng quản lý đối tượng được sử dụng cho điều đó (ít nhất là trong jpa mở). Bạn cũng có thể chạy truy vấn với trình quản lý thực thể này. Nó không có sql nhưng JPQL (ngôn ngữ truy vấn tồn tại Java).

đơn giản ví dụ:

emf = Persistence.createEntityManagerFactory("localDB"); 
em = emf.createEntityManager(); 

Query q = em.createQuery("select u from Users as u where u.username = :username", Users.class); 
q.setParameter("username", username); 

List<Users> results = q.getResultList(); 

em.close(); 
emf.close(); 
14

Một điều chắc chắn: nếu bạn sử dụng EntityManager trên lớp dịch vụ, bạn không cần một lớp dao (chỉ có một lớp nên biết chi tiết thực hiện). Bên cạnh đó, có những ý kiến ​​khác nhau:

  • Một số người nói các EntityManager lộ tất cả các chức năng cần thiết dao, vì vậy họ tiêm EntityManager trong lớp dịch vụ .
  • Những người khác có lớp dao truyền thống được hỗ trợ bởi giao diện (do đó, dịch vụ lớp không được gắn với việc triển khai chi tiết ).

Cách tiếp cận thứ hai thanh lịch hơn khi chia tách các mối quan tâm và nó cũng sẽ chuyển từ công nghệ bền vững này sang công nghệ mới khác (bạn chỉ cần thực hiện lại giao diện dao với công nghệ mới), nhưng nếu bạn biết rằng không có gì thay đổi, thì thứ nhất sẽ dễ dàng hơn.

Tôi muốn nói nếu bạn có một dự án nhỏ, hãy sử dụng JPA trong lớp dịch vụ, nhưng trong một dự án lớn sử dụng một lớp DAO chuyên dụng.

+0

trong ví dụ của bạn trình quản lý đối tượng là DAO – walnutmon

+0

trong ví dụ đầu tiên, có –

+1

+1. Thật vậy trong các dự án lớn hơn, lớp dịch vụ phải là cơ chế bền vững bất khả tri. – Bozho

4

Theo truyền thống, bạn sẽ viết giao diện xác định hợp đồng giữa lớp dịch vụ và lớp dữ liệu. Sau đó bạn viết triển khai và đây là các DAO của bạn.

Quay lại ví dụ của bạn. Giả sử mối quan hệ giữa sân bay và hãng hàng không là rất nhiều với một bảng chứa airport_id và flight_id bạn có thể có một giao diện;

public interface AirportDAO 
{ 
    public List<Airline> getAirlinesOperatingFrom(Set<Airport> airports); 
} 

..và bạn có thể cung cấp một Hibernate thực hiện điều này;

public class HibernateAirportDAO implements AirportDAO 
{ 
    public List<Airline> getAirlinesOperatingFrom(Set<Airport> airports) 
    { 
     //implementation here using EntityManager. 
    } 
} 

Bạn cũng có thể xem Danh sách trên thực thể Hãng hàng không và xác định mối quan hệ với chú thích @ManyToMany JPA. Điều này sẽ loại bỏ sự cần thiết phải có phương pháp DAO cụ thể này hoàn toàn.

Bạn cũng có thể muốn xem xét mẫu Nhà máy Tóm tắt để viết các nhà máy DAO. Ví dụ;

public abstract class DAOFactory 
{ 
    private static HibernateDAOFactory hdf = new HibernateDAOFactory(); 

    public abstract AirportDAO getAirlineDAO(); 

    public static DAOFactory getFactory() 
    { 
     //return a concrete implementation here, which implementation you 
     //return might depend on some application configuration settings. 
    } 
} 

public class HibernateDAOFactory extends DAOFactory 
{ 
    private static EntityManagerFactory emFactory = Persistence.createEntityManagerFactory("myPersistenceUnit"); 

    public static EntityManager getEM() 
    { 
     return emFactory.createEntityManager(); 
    } 

    public AirportDAO getAirportDAO() 
    { 
     return new HibernateAirportDAO(); 
    } 
} 

Mẫu này cho phép HibernateDAOFactory giữ EMF duy nhất và cung cấp cá thể DAO riêng lẻ với EM. Nếu bạn không muốn đi xuống con đường fatory thì Spring là tuyệt vời tại xử lý các trường hợp DAO cho bạn với tiêm phụ thuộc.

Chỉnh sửa: Làm rõ một vài giả định.

+0

có, nhưng không phải là việc trộn các lớp kinh doanh/dịch vụ và truy cập dữ liệu phải không? tôi đặc biệt có nghĩa là getAirlinesOperatingFrom(). hoặc là thực hành tốt này? đó là dự án đầu tiên của tôi trong lĩnh vực này, vì vậy tôi không chắc chắn –

+1

Cách tiếp cận nhà máy này không có ý nghĩa trong một kịch bản mùa xuân. –

+0

@seanizer Vâng, với Spring OP có thể muốn cấu hình DAO của mình như là một phần của bối cảnh ứng dụng của mình và tiêm chúng. – Qwerky

5

Đây là article bởi Adam Bien có thể hữu ích.

Các vấn đề liên quan