2010-08-17 41 views
7

Dưới đây là các phương pháp tôi hiện có trong lớp Tóm tắt DAO. Nếu có các cuộc gọi đồng thời, chúng có an toàn không hoặc chúng nên được đồng bộ hóa hay không? Tôi biết đồng bộ hóa nên được sử dụng nếu có một tham chiếu đến một thuộc tính bên ngoài phạm vi của một phương pháp nhưng nó không rõ ràng với tôi như thế nào những điều cần được xử lý với một ressource bên ngoài.Phương pháp DAO và đồng bộ

public Connection getConnection() { 
    // Call to singleton handling JDBC stuff 
    return Database.getInstance().getCon(); 
} 

public boolean isConnectionAvailable(){  
    if(getConnection() != null){ 
     return true; 
    } 

    return false; 
} 

public PreparedStatement getPreparedStatement(String sqlStatement){ 
    Connection connection = getConnection(); 
    PreparedStatement pS = null; 

    if(connection != null){ 
     try { 
      pS = connection.prepareStatement(sqlStatement); 
     } catch (SQLException e) { 
      return null; 
     } 
    } 

    return pS; 
} 

Chỉnh sửa: Tôi có thể sửa đổi câu hỏi này để bao gồm thông tin về viết DAO vì đây là điều quan trọng ở đây.

+3

không làm không sử dụng đơn để truy cập kết nối cơ sở dữ liệu –

+0

Tôi thường nghe điều đó. Nhưng thay thế khi bạn làm việc với Java thuần túy là gì? –

Trả lời

12

Tôi hoàn toàn không đồng ý với việc triển khai này.

Đầu tiên, DAO phải được cung cấp thông tin kết nối của họ bằng các dịch vụ sở hữu đơn vị công việc và giao dịch.

Thứ hai, tôi không thấy giao diện.

Thứ ba, tôi không thấy mô hình hoặc đối tượng tên miền.

Thứ tư, các câu được chuẩn bị chỉ nên là một phần của việc triển khai nội bộ. Nếu chúng bị rò rỉ ra khỏi DAO của bạn, bạn đang làm sai.

Thứ năm, chuyển một tuyên bố đã chuẩn bị ra khỏi đối tượng có trách nhiệm đóng nó và dọn dẹp ít rõ ràng hơn. DAO của bạn sẽ chết một cái chết rò rỉ tài nguyên trong thời gian không.

Đây là giao diện cho DAO chung. Bạn sẽ nhận thấy rằng đó là tất cả các hoạt động CRUD, không đề cập đến các kết nối hoặc bất kỳ giao diện nào từ java.gói sql:

package persistence; 

import java.io.Serializable; 
import java.util.List; 

public interface GenericDao<T, K extends Serializable> 
{ 
    T find(K id); 
    List<T> find(); 
    List<T> find(T example); 
    List<T> find(String queryName, String [] paramNames, Object [] bindValues); 

    K save(T instance); 
    void update(T instance); 
    void delete(T instance); 
} 

Bạn có thể đi một chặng đường dài với điều này. Đó là một trừu tượng tốt hơn. T là loại đối tượng kinh doanh của bạn và K là khóa chính.

+2

Mùa xuân có khung DAO phong nha: http://static.springsource.org/spring/docs/2.5.x/reference/dao.html – Dave

+0

Hơn cả phong nha. Đây là mô hình để làm theo. – duffymo

+0

Cảm ơn bạn đã trả lời câu hỏi. Tôi phải thừa nhận rằng tôi đang đấu tranh một chút như tôi đã được yêu cầu không sử dụng một khuôn khổ như Spring. nếu bạn có một ví dụ có thể được sử dụng làm mẫu, nó sẽ được chào đón nhiều hơn :). –

3

Nếu getCon() trả về một mới Connection mỗi lần nó được gọi, hoặc trả về một kết nối ThreadLocal, sau đó bạn được an toàn và không có nhu cầu sử dụng synchronized

Nếu bạn quay lại cùng một kết nối đến tất cả mọi người bạn vẫn có thể tiết kiệm về mặt đồng bộ hóa, vì không có trạng thái nào trong kết nối được thay đổi (trong mã hiện tại của bạn). Nhưng bạn nên tránh thực hành này. Thay vào đó hãy xem xét một nhóm kết nối.

Và một số lưu ý về nguyên tắc thiết kế chung. DAO tạo thành một lớp riêng biệt. Mỗi lớp tồn tại vì một lý do, không phải là juts vì có tên mát mẻ. Lớp DAO tồn tại để trừu tượng, hoặc nói cách khác - ẩn truy cập cơ sở dữ liệu từ các dịch vụ sử dụng các đối tượng DAO. Để tưởng tượng rõ ràng hơn - DAO phải được viết theo cách mà nếu ngày mai bạn quyết định chuyển từ lưu trữ RDBMD (qua JDBC) sang lưu trữ XML, bạn có thể làm điều đó bằng cách thay đổi chỉ đối tượng DAO và không có gì khác.

+0

Các lớp DAO cụ thể hoạt động như bạn đã giải thích. Các phương thức trên chỉ là một ý tưởng để thêm một số phương thức tiện ích trong lớp Asbtract nhưng có lẽ đây là một cách tiếp cận xấu. Những gì tôi có lẽ chưa hiểu là làm thế nào nó nên tương tác với JDBC và một cơ sở dữ liệu. –

3

Lớp kết nối JDBC không được đảm bảo là luồng an toàn. Nếu phương thức Database.getInstance() của bạn getCon() luôn trả về cùng một kết nối, thì bạn sẽ gặp vấn đề. Nếu, tuy nhiên, nó đang sử dụng một hồ bơi như vậy mà mỗi cuộc gọi đến getInstance(). GetCon() trả về một kết nối khác nhau, bạn sẽ được sử dụng tốt.

Điều đó nói rằng, nếu bạn đang trả về kết nối khác nhau với mỗi lệnh gọi hàm getCon() thì getPreparedStatement() sẽ không hoạt động nếu bạn muốn hai lệnh gọi đã được chuẩn bị sử dụng cùng một kết nối (và cùng một giao dịch).

Tôi thích lớp JDBCTemplate của Spring làm cơ sở cho các lớp DAO của tôi.

+0

'Kết nối' chỉ là một giao diện, cho dù các triển khai có an toàn luồng không hoàn toàn phụ thuộc vào trình điều khiển JDBC đang được sử dụng hay không –

+0

Điểm tốt. Tôi đã cập nhật câu trả lời của mình để làm rõ điều này. – Dave

0

Có vẻ ổn với tôi. Các chức năng là Thread an toàn.

2

Bạn không nên sử dụng cùng một kết nối trong mỗi chuỗi. Trình điều khiển JDBC không phải là luồng an toàn. Nếu bạn muốn có một mã an toàn chủ đề, bạn nên tạo một kết nối cho mỗi luồng.

Phần còn lại của mã của bạn có vẻ an toàn.

+0

Bạn có nghĩ rằng tôi nên thêm một số loại mecanism luồng bên trong DAO? –

+0

Nó không phải là DAO của bạn mà không phải là chủ đề an toàn, đó là phần kết nối. Giống như @Bozho nói nếu getCon() trả về mỗi lần một kết nối cụ thể cho mỗi luồng thì không có điều kiện chủng tộc. –

+0

Ok, vậy điều bạn đang nói là tôi nên cách ly bất kỳ truy cập nào với kết nối. Tôi đã có một cái nhìn trong singleton và nó trả về cùng một kết nối mỗi lần để có thể là một vấn đề. –

2

Hãy xem cách Spring thực hiện, họ đã tìm ra tất cả những thứ này và không cần phải phát minh lại nó. Kiểm tra mã mẫu petclinic đi kèm với bản phân phối đầy đủ của Spring, hoặc (đối với phương pháp không phải Spring) đọc chương DAO của sách Bauer/King Hibernate.

Chắc chắn DAO không được phụ trách nhận kết nối cơ sở dữ liệu, vì bạn sẽ muốn nhóm nhiều cuộc gọi DAO trong cùng một giao dịch. Cách mà Spring thực hiện là có một lớp dịch vụ được các phương thức giao dịch của nó được bao bọc trong một bộ chặn chặn lấy kết nối từ nguồn dữ liệu và đặt nó trong một biến chủ đề nơi DAO có thể tìm thấy nó.

Ăn SQLException của bạn và trả về giá trị rỗng là xấu. Như duffymo chỉ ra, cho phép PreparedStatement được thông qua xung quanh mà không đảm bảo rằng nó sẽ bao giờ đóng cửa là rất xấu. Ngoài ra, không ai nên sử dụng JDBC thô nữa, Ibatis hoặc spring-jdbc là lựa chọn thay thế tốt hơn.

+0

-1 cho "không ai nên sử dụng JDBC thô nữa". – GreenieMeanie

+0

-1 dường như hơi khắc nghiệt. Bạn đã bao giờ sử dụng jdbc mùa xuân chưa? Nó gần như là jdbc thô, nơi bạn vẫn sẽ thao tác ps và rs (nếu bạn muốn) nhưng với tất cả xử lý ngoại lệ (và quản lý tài nguyên) và tương tác với tx được quan tâm. Vì vậy, bạn có lợi thế về truy cập dữ liệu thô với ít rủi ro bị rò rỉ hơn. – Thierry

+0

Tôi nghĩ đó là một vị trí có thể bảo vệ được, GreenieMeanie.Tôi muốn mọi người sử dụng Spring chỉ cho JDBC thay vì mã JDBC ghê tởm mà tôi thấy trên SO. Tôi đã bỏ phiếu cho Nathan Hughes. – duffymo

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