2010-04-02 38 views
13

Trong tham chiếu Hibernate, nó được ghi nhiều lần rằngLàm cách nào để ngắt phiên Hibernate?

Tất cả ngoại lệ do Hibernate ném đều gây tử vong. Điều này có nghĩa là bạn phải quay lại giao dịch cơ sở dữ liệu và đóng số Session hiện tại. Bạn không được phép tiếp tục làm việc với một số Session đã ném một ngoại lệ.

Một trong các ứng dụng cũ của chúng tôi sử dụng một phiên duy nhất để cập nhật/chèn nhiều bản ghi từ tệp vào bảng DB. Mỗi bản ghi cập nhật/chèn được thực hiện trong một giao dịch riêng biệt, sau đó được cam kết (hoặc quay lại trong trường hợp xảy ra lỗi). Sau đó, đối với bản ghi tiếp theo, một giao dịch mới được mở, và cứ thế. Nhưng cùng một phiên được sử dụng trong suốt toàn bộ quá trình, ngay cả khi một HibernateException bị bắt ở giữa quá trình xử lý. Chúng tôi đang sử dụng Oracle 9i btw với Hibernate 3.24.sp1 trên JBoss 4.2.

Đọc phần trên trong sách, tôi nhận ra rằng thiết kế này có thể không thành công. Vì vậy, tôi đã tái cấu trúc ứng dụng để sử dụng một phiên riêng biệt cho mỗi bản cập nhật bản ghi. Trong một thử nghiệm đơn vị với một nhà máy sản xuất phiên giả lập, tôi có thể xác minh rằng nó đang yêu cầu một phiên mới cho mỗi lần cập nhật bản ghi. Càng xa càng tốt.

Tuy nhiên, chúng tôi không tìm thấy cách nào để tạo lại lỗi phiên trong khi kiểm tra toàn bộ ứng dụng (đây có phải là thử nghiệm căng thẳng btw hay không?). Chúng tôi đã nghĩ đến việc tắt người nghe DB nhưng chúng tôi nhận ra rằng ứng dụng đang giữ một loạt các kết nối mở cho DB và người nghe sẽ không ảnh hưởng đến các kết nối đó. (Đây là một ứng dụng web, được kích hoạt một lần mỗi đêm bởi một trình lên lịch, nhưng nó cũng có thể được kích hoạt thông qua trình duyệt.) Sau đó, chúng tôi đã cố gắng giết một số kết nối đó trong DB trong khi ứng dụng đang xử lý các bản cập nhật. cập nhật, nhưng sau đó ứng dụng vui vẻ tiếp tục cập nhật phần còn lại của các bản ghi. Rõ ràng Hibernate là đủ thông minh để mở lại các kết nối bị hỏng dưới mui xe mà không vi phạm toàn bộ phiên.

Vì vậy, điều này có thể không phải là vấn đề quan trọng, vì ứng dụng của chúng tôi dường như đủ mạnh ngay cả ở dạng ban đầu. Tuy nhiên, vấn đề vẫn tiếp tục làm tôi thất vọng. Tôi muốn biết:

  1. Trong hoàn cảnh nào không phiên Hibernate thực sự trở thành không sử dụng được sau một HibernateException bị ném (Cập nhật: và các triệu chứng là gì)?
  2. Làm thế nào để tái tạo điều này trong một bài kiểm tra (Cập nhật: tốt hơn là trong tích hợp, thay vì kiểm tra đơn vị)?
  3. (thuật ngữ thích hợp cho một thử nghiệm như vậy là gì?)

Trả lời

4

Trong hoàn cảnh nào không phiên Hibernate thực sự trở thành không sử dụng được sau một HibernateException bị ném?

Câu hỏi thú vị. Tôi khá chắc chắn rằng tôi đã nhìn thấy trường hợp phiên họp vẫn còn "làm việc" sau khi một ngoại lệ như vậy. Vấn đề có thể là điều này không được đảm bảo. Tôi sẽ cần đào thêm một chút nữa.

Cập nhật: Trích dẫn this message từ một nhà phát triển Hibernate trong các diễn đàn Hibernate:

Phiên ngủ đông nên vứt bỏ khi bất kỳ ngoại lệ xảy ra.Nó có thể được trái trong một trạng thái không nhất quán liên quan đến cơ sở dữ liệu. Đây không phải là trường hợp với một phiên chỉ đọc vì nó không sử dụng bất kỳ bộ nhớ đệm cấp phiên. Ngoài ra, bạn có thể xóa bộ nhớ cache cấp phiên khi một ngoại lệ xảy ra (nhưng tôi không đích thân thích cách tiếp cận này vì nó không phải là giải pháp sạch và có thể dẫn đến các sự cố và vấn đề trong tương lai).

Vì vậy, vấn đề là không thực sự nếu Session là "có thể sử dụng về mặt kỹ thuật" hay không, vấn đề là nó có thể không hoạt động như mong đợi. Và bạn rõ ràng không muốn điều đó.

Làm thế nào để tái tạo điều này trong thử nghiệm?

Bạn có thể cố ý vi phạm điều kiện gây ra phân lớp được ném, ví dụ: vi phạm ràng buộc toàn vẹn để có được ConstraintViolationException. Điều gì về một cái gì đó như thế:

Session session = HibernateUtil.getCurrentSession(); 

try { 
    session.beginTransaction();  
    // execute some code that violates a unique constraint 
    ... 
    session.getTransaction().commit(); 
} catch (HibernateException e) { 
    session.getTransaction().rollback(); 
} 

// keep using the session 
try { 
    session.beginTransaction();  
    ... 
    session.getTransaction().commit(); 
} catch (HibernateException e) { 
    session.getTransaction().rollback(); 
} 
// do we reach this point? 

Nhưng tôi không chắc chắn điều này sẽ chứng minh bất cứ điều gì. Ý tôi là, nếu phiên làm việc vẫn đang hoạt động, chúng tôi chỉ có thể kết luận cho trường hợp cụ thể này.

Cập nhật: Hãy quên đề xuất của tôi, nó sẽ không chứng minh điều gì. Và trên thực tế, tôi nghĩ rằng nó sẽ vô cùng phức tạp (kỹ thuật và chức năng) để chứng minh rằng mọi thứ đang hoạt động như mong đợi (và đó vẫn có thể là "tai nạn") sau HibernateException. Vì vậy, thay vì cố gắng chứng minh bất cứ điều gì, tôi đoán rằng điều đúng đắn phải làm là tuân theo khuyến nghị (hoặc đề nghị thay thế nhưng tôi sẽ yêu cầu Sessionclose mới cho mọi giao dịch, ngoại lệ được ném hay không).

Thuật ngữ thích hợp cho thử nghiệm như vậy là gì?

Kiểm tra tích hợp? Kiểm tra độ bền?

1

Quan điểm của tôi về vấn đề này là

  1. It't bên cạnh không thể biết nếu Hibernate sẽ làm việc, nó gặp phải một tình huống bất ngờ và hiện đang chạy trong trạng thái không xác định - Về cơ bản, bạn sẽ được gọi UB bằng cách thực hiện thêm bất kỳ thao tác nào trong phiên.

  2. Idea - đăng ký một đánh chặn và ném một HibernateException trong nó - hy vọng rằng Hibernate sẽ không bắt nó: D tiêm

  3. lỗi?

+0

Về 1), đây cũng là sự hiểu biết của tôi - vì vậy tôi rất vui vì tôi đã làm cho ứng dụng của chúng tôi mạnh mẽ hơn. Vấn đề trực tiếp là, làm thế nào để xác minh điều này trong một thử nghiệm độc lập? 2) âm thanh thú vị, vì điều này có thể được thực hiện mà không cần sửa đổi bản thân ứng dụng. –

3

Thú vị nhất. Cách tốt nhất để nói là đi và xem xét các nguồn của Hibernate.Theo như tôi nhận được nó, các Session không mang nhiều trạng thái xung quanh, ngoại trừ những thứ sau đây:

  • bộ nhớ cache đầu tiên cấp (xem StatefulPersistenceContext) - nó có thể được thực sự bị phá vỡ sau khi thực hiện giao dịch;
  • hàng đợi hành động (xem ActionQueue) - dường như không sao nếu bạn thực hiện xả bằng tay;
  • nghe sự kiện - trường hợp họ nhận thức được phiên (xem EventSource) và, như bạn có thể nhận thấy, những trường hợp ngoại lệ JDBC luôn gây ra bởi đỏ bừng (DefaultFlushEventListener, để được chính xác hơn), nhưng xem lướt qua AbstractFlushingEventListener cho thấy rằng họ thực sự làm việc với phiên của JDBCContextActionQueue.

Và điều cuối cùng, việc tự khôi phục giao dịch không ảnh hưởng đến trạng thái Phiên theo bất kỳ cách nào, xem JDBCTransaction.

Vì vậy, theo như tôi đã chơi xung quanh, Session thực sự tồn tại một giao dịch bị lỗi, ngoại trừ bộ nhớ cache cấp một có thể hơi không chính xác; để giải quyết vấn đề này, bạn có thể muốn gọi tới số session.refresh hoặc session.load để các trạng thái đồng bộ hóa rõ ràng.

EDIT: cách nhanh nhất để kiểm tra ngoại lệ JDBC có lẽ session.createSQLQuery("something offensive to SQL parser").executeUpdate() - bạn sẽ có được một hoàn hảo SQLGrammarException - và một giao dịch bị hỏng =)

0

Tạo một lớp con của phiên để thử nghiệm. Thực hiện nó để ném một ngoại lệ trong một số kịch bản cụ thể. Sử dụng cấu hình hibernate thử nghiệm cụ thể, thiết lập chế độ ngủ đông để sử dụng Phiên thử nghiệm của bạn.

+0

Điều này ném một HibernateException thực sự, nhưng nó không ảnh hưởng đến trạng thái của phiên Hibernate chính nó. Nói cách khác, đây chỉ là một phiên làm việc được thực hiện bằng tay. –

+0

có lẽ tôi không hiểu những gì bạn đang tìm kiếm sau đó. bạn đang tìm kiếm một cách đáng tin cậy để đặt ngủ đông vào trạng thái bị hỏng (ví dụ: không xác định)? và rồi chuyện gì xảy ra? – james

+0

Tôi đang tìm một cách đáng tin cậy để đưa phiên Hibernate vào trạng thái bị hỏng, do đó phiên bản cũ hơn của ứng dụng của chúng tôi (sử dụng lại cùng một phiên trên các giao dịch) không thành công và phiên bản mới hơn (được phiên mới cho mỗi giao dịch)) vượt qua bài kiểm tra. –

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