2009-03-19 21 views
5

Chúng tôi đang gặp phải lỗi Oracle Deadlock (org.hibernate.util.JDBCExceptionReporter - ORA-00060: bế tắc được phát hiện khi đang chờ tài nguyên). Nó đã được gợi ý rằng vấn đề là với một quá trình đó là thực hiện hoạt động chỉ đọc bằng cách sử dụng Hibernate trong khi một quá trình đang thực hiện một bản cập nhật trên cùng một hàng.Oracle Deadlock khi ứng dụng tải dữ liệu Hibernate để sử dụng chỉ đọc

Quy trình chỉ đọc được đề cập được định cấu hình bằng Hibernate và Spring. Chúng tôi chưa xác định rõ ràng giao dịch cho dịch vụ. Trong khi đó có thể không lý tưởng - Tôi không thấy tại sao Hibernate sẽ cố gắng để có được một khóa độc quyền trên một hàng khi không lưu/cập nhật các hoạt động đã được thực hiện - chỉ có được/tải. Vì vậy, câu hỏi của tôi là: Có Hibernate, khi không có quản lý giao dịch rõ ràng được xác định, cố gắng để có được một khóa đọc/ghi trên một hàng ngay cả khi chỉ có một "tải" của một đối tượng được thực hiện. Không Lưu/Cập nhật được thực hiện.

Có thể xác định giao dịch xung quanh dịch vụ đang tải dữ liệu và sau đó nói READONLY trên transactionAttributes sẽ khiến Hibernate bỏ qua một hàng khóa đã tồn tại và chỉ tải dữ liệu cho mục đích chỉ đọc?

Dưới đây là một số ví dụ mã:

Đối tải kỷ lục chúng tôi đang sử dụng một HibernateDaoTemplate

public class HibernatePurchaseOrderDataService extends HibernateDaoSupport implements PurchaseOrderDataService { 
    public PurchaseOrderData retrieveById(Long id) { 
     return (PurchaseOrderData)getHibernateTemplate().get(PurchaseOrderData.class, id); 
    } 
} 

Các cấu hình Spring cho dịch vụ gọi phương pháp này là:

<bean id="orderDataService" 
     class="com.example.orderdata.HibernatePurchaseOrderDataService"> 
    <property name="sessionFactory" ref="orderDataSessionFactory"/> 
</bean> 

<bean id="orderDataSessionFactory" 
     class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
    <property name="dataSource" ref="hibernateDataSource"/> 
    <property name="hibernateProperties" ref="hibernateProperties"/> 
    <property name="mappingResources"> 
     <list> 
      <value>com/example/orderdata/PurchaseOrderData.hbm.xml</value> 
      <value>com/example/orderdata/PurchaseOrderItem.hbm.xml</value> 
     </list> 
    </property> 
</bean> 

Các thực tế bế tắc đang xảy ra trên một trong các bản ghi PurchaseOrderItem đang được nạp bởi lệnh gọi nạp PurchaseOrder.

Điều này có gây ra bế tắc nếu bản ghi đang được tải đã bị khóa bởi một quy trình khác không? Và nếu vậy - sẽ thêm một trình bao bọc giao dịch như trình bao dưới đây giải quyết vấn đề?

<bean id="txWrappedOrderDataService" 
     class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> 
    <property name="transactionManager" ref="transactionManager"/> 
    <property name="target" ref="orderDataService"/> 
    <property name="transactionAttributes"> 
    <props> 
     <!-- all methods require a transaction --> 
     <prop key="*">PROPAGATION_REQUIRED,readOnly</prop> 
    </props> 
    </property> 
</bean> 

Cập nhật: Nhóm DataBase đã nhìn thấy quá trình "chỉ đọc" của chúng tôi thực sự ghi vào cơ sở dữ liệu tự động. Có các lệnh "UPDATE" đã đăng nhập được thực hiện trên các cột chính xác mà chúng ta đang đọc từ cơ sở dữ liệu. Dường như Hibernate tự động viết những bản ghi này trở lại cơ sở dữ liệu (mặc dù chúng tôi không yêu cầu nó). Điều đó có lẽ sẽ giải thích tại sao có bế tắc.

Điều này có thể là do phiên FLUSH hoặc điều gì đó tương tự không? Nhìn giống như giải pháp có thể là sử dụng trình bao bọc giao dịch với readOnly trên đó ...

Trả lời

1

Cuối cùng chúng tôi đã xác định rằng giải pháp là để bọc nó trong một giao dịch readOnly.

Tôi không rõ lý do tại sao, chúng tôi không sử dụng trình cài đặt nào cả (chỉ cần đọc dữ liệu) - không có gì thay đổi trong cơ sở dữ liệu. Nhưng vì lý do nào đó Hibernate đã cố gắng viết lại cùng một dữ liệu và đã gây ra một khóa khi một quá trình khác cố gắng đọc những bản ghi đó.

Sử dụng giao dịch readOnly khiến vấn đề biến mất!

<bean id="txWrappedOrderDataService" 
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> 
<property name="transactionManager" ref="transactionManager"/> 
<property name="target" ref="orderDataService"/> 
<property name="transactionAttributes"> 
    <props> 
     <!-- all methods require a transaction --> 
     <prop key="*">PROPAGATION_REQUIRED,readOnly</prop> 
    </props> 
</property> 

0

Bạn đã kiểm tra bất kỳ trình kích hoạt nào trong cơ sở dữ liệu chưa? Bạn có chắc chắn nó là Hibernate và không phải một số quá trình khác cập nhật những hàng tương tự? Có thể có một cột lưu trữ một dấu thời gian của lần đọc cuối cùng và nó được cập nhật mỗi khi hàng được đọc (Mặc dù tôi không thể nhớ ra khỏi đầu của tôi mà bạn có thể kích hoạt SELECT) ...

2

Không tự nguyện cập nhật có thể xảy ra với hibernate khi bạn sử dụng setters thao tác giá trị mà họ thực sự thiết lập. Một ví dụ sẽ là một setter cho một thuộc tính String thay thế một giá trị null bằng "". Một ứng cử viên có khả năng cũng là các bộ sưu tập. Hãy chắc chắn rằng setters không thay thế bộ sưu tập chứa. Nếu bạn thay thế một bộ sưu tập của một thực thể với một bộ sưu tập khác có chứa cùng nội dung, hibernate sẽ không thể nhận ra và cập nhật toàn bộ bộ sưu tập.

+0

Đây không phải là chính xác những gì đã xảy ra - nhưng có vẻ tương tự. Các giá trị không được "đặt" trong mã. Hibernate đã thực sự cố gắng để viết lại cùng một dữ liệu cho một số lý do (dữ liệu trong DB không bao giờ được cập nhật các giá trị khác nhau). – jonathanq

0

Jens là đúng

Để thêm on-bạn cần phải kiểm tra chặt chẽ setters và thu khí của bạn và xem nếu họ trả về một giá trị khác nhau cho các cuộc gọi khác nhau ví dụ new Date() - điều này sẽ trả về một giá trị gia tăng mới mỗi thời gian được gọi và sẽ làm cho ngủ đông nghĩ rằng đối tượng đã thay đổi

0

Một điều thú vị để làm là thêm

log4j.logger.org.hibernate.persister.entity.AbstractEntityPersister = TRACE

trong cấu hình log4j của bạn. Bằng cách làm điều đó hibernate sẽ đăng nhập lý do tại sao một thực thể cần cập nhật trong cơ sở dữ liệu. Chúng tôi đã gặp một số vấn đề với các thực thể trả về "" khi một thuộc tính không có gì gây ra các cập nhật trong DB. Bằng cách đó, chúng tôi đã có thể xác định các vấn đề như vậy.

0

Tôi đã thấy sự cố này xảy ra trong hệ thống của mình khi chúng tôi thiếu chỉ mục. Các truy vấn đang được thực thi trong cơ sở dữ liệu đang chạy quá lâu do thiếu các chỉ mục trên các cột khóa, do đó khóa bảng.

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