2010-03-22 45 views
6

Tôi vẫn còn trong quá trình học hibernate/hql và tôi có một câu hỏi đó là một nửa thực hành tốt nhất câu hỏi/kiểm tra sanity một nửa.câu hỏi độc đáo cột ngủ đông

Hãy nói rằng tôi có một lớp A:

@Entity 
public class A 
{ 
    @Id @GeneratedValue(strategy=GenerationType.AUTO) 
    private Long id; 

    @Column(unique=true) 
    private String name = ""; 

    //getters, setters, etc. omitted for brevity 
} 

Tôi muốn thực thi mà mỗi trường hợp của A mà được lưu có một cái tên duy nhất (vì thế chú thích @column), nhưng tôi cũng muốn có thể để xử lý trường hợp đã có một cá thể A được lưu có tên đó. Tôi thấy hai cách để làm điều này:

1) Tôi có thể bắt org.hibernate.exception.ConstraintViolationException có thể được ném trong cuộc gọi session.saveOrUpdate() và cố gắng xử lý nó.

2) Tôi có thể truy vấn các phiên bản hiện tại của A đã có tên đó trong DAO trước khi gọi session.saveOrUpdate().

Hiện tại tôi đang nghiêng về phía phương pháp 2, vì trong phương pháp tiếp cận 1 Tôi không biết cách lập trình tìm ra ràng buộc nào đã bị vi phạm (có một vài thành viên duy nhất khác trong A). Ngay bây giờ mã DAO.save() của tôi trông gần giống như thế này:

public void save(A a) throws DataAccessException, NonUniqueNameException 
{ 
    Session session = sessionFactory.getCurrentSession(); 

    try 
    { 
     session.beginTransaction(); 

     Query query = null; 

     //if id isn't null, make sure we don't count this object as a duplicate 
     if(obj.getId() == null) 
     { 
      query = session.createQuery("select count(a) from A a where a.name = :name").setParameter("name", obj.getName()); 
     } 
     else 
     { 
      query = session.createQuery("select count(a) from A a where a.name = :name " + 
       "and a.id != :id").setParameter("name", obj.getName()).setParameter("name", obj.getName()); 
     } 

     Long numNameDuplicates = (Long)query.uniqueResult(); 
     if(numNameDuplicates > 0) 
      throw new NonUniqueNameException(); 

     session.saveOrUpdate(a); 
     session.getTransaction().commit(); 
    } 
    catch(RuntimeException e) 
    { 
      session.getTransaction().rollback(); 
      throw new DataAccessException(e); //my own class 
    } 
} 

Tôi sẽ làm điều này đúng cách? Có thể ngủ đông cho tôi biết theo chương trình (tức là không phải là chuỗi lỗi) giá trị nào vi phạm ràng buộc duy nhất không? Bằng cách tách truy vấn khỏi cam kết, tôi có đang mời các lỗi an toàn luồng không hoặc tôi có an toàn không? Việc này thường được thực hiện như thế nào?

Cảm ơn!

Trả lời

3

Tôi nghĩ rằng cách tiếp cận thứ hai của bạn là tốt nhất.

Để có thể bắt ngoại lệ ConstraintViolation với bất kỳ sự chắc chắn nào mà đối tượng cụ thể này gây ra nó, bạn sẽ cần phải xả phiên ngay sau khi cuộc gọi đến saveOrUpdate. Điều này có thể giới thiệu các vấn đề hiệu suất nếu bạn cần chèn một số các đối tượng này cùng một lúc.

Mặc dù bạn sẽ kiểm tra nếu tên đã tồn tại trong bảng trên mọi hành động lưu, điều này sẽ vẫn nhanh hơn xả sau mỗi lần chèn. (Bạn luôn có thể điểm chuẩn để xác nhận.)

Điều này cũng cho phép bạn cấu trúc mã của mình theo cách mà bạn có thể gọi là 'trình xác thực' từ một lớp khác. Ví dụ: nếu thuộc tính duy nhất này là email của người dùng mới, từ giao diện web, bạn có thể gọi phương thức xác thực để xác định xem địa chỉ email có được chấp nhận hay không. Nếu bạn đã đi với tùy chọn đầu tiên, bạn sẽ chỉ biết nếu email đã được chấp nhận sau khi cố gắng chèn nó.

+0

Tôi có gặp vấn đề về an toàn luồng nào với phương pháp thứ hai không? Theo như tôi hiểu, phần "Cách ly" của các nguyên tắc DB của ACID được cho là sẽ giúp tôi ở đây, nhưng tôi không chắc cách hibernate/hsqldb tuân thủ như thế nào. – Seth

+0

Tôi không hiểu tại sao cách ly lại quan trọng đối với trường hợp này. Kiểm tra nếu một tên tồn tại sẽ xảy ra trong cùng một giao dịch và không thay đổi trạng thái của dữ liệu trong cơ sở dữ liệu. – Rachel

1

Tiếp cận 1 sẽ là ok nếu:

  • Chỉ có một hạn chế trong thực thể.
  • Chỉ có một đối tượng bẩn trong phiên.

Hãy nhớ rằng đối tượng có thể không được lưu cho đến khi flush() được gọi hoặc giao dịch được cam kết.

Đối với lỗi tốt nhất báo cáo tôi sẽ:

  1. Sử dụng cách tiếp cận hai cho mỗi vi phạm hạn chế, vì vậy tôi có thể đưa ra một lỗi cụ thể cho mỗi trong số họ ..
  2. Thực hiện một đánh chặn rằng trong trường hợp của một chế ngoại lệ thử lại giao dịch (số lần tối đa) để vi phạm không thể bị phát hiện trong một trong các thử nghiệm. Điều này chỉ cần thiết tùy thuộc vào mức cô lập giao dịch.