2009-03-19 11 views
5

Występuje błąd Oracle Deadlock (org.hibernate.util.JDBCExceptionReporter - ORA-00060: zakleszczenie wykryte podczas oczekiwania na zasoby). Sugerowano, że problem dotyczy procesu, który wykonuje operacje tylko do odczytu przy użyciu Hibernuj, podczas gdy inny proces wykonuje aktualizację w tym samym wierszu.Zakleszczenie Oracle, gdy aplikacja Hibernate ładuje dane do użycia tylko raz.

Proces typu "tylko do odczytu" jest konfigurowany przy użyciu trybu hibernacji i wiosny. Nie zdefiniowaliśmy jawnie transakcji dla usługi. Chociaż może to nie być idealne - nie widzę powodu, dla którego Hibernate spróbuje uzyskać wyłączną blokadę w wierszu, gdy nie są wykonywane operacje zapisu/aktualizacji - tylko get/load.

Moje pytanie brzmi: Czy w trybie hibernacji, gdy nie zdefiniowano jawnego zarządzania transakcjami, spróbuj uzyskać blokadę odczytu/zapisu w wierszu, nawet jeśli wykonywane jest tylko "obciążenie" obiektu. Nie wykonano zapisu/aktualizacji.

Czy jest możliwe, że zdefiniowanie transakcji wokół usługi, która ładuje dane, a następnie konkretne POWIADOMIENIE w atrybucie transakcji spowoduje, że Hibernate zignoruje istniejącą blokadę wiersza i po prostu załaduje dane do celów tylko do odczytu?

Oto niektóre przykłady kodu:

do załadunku rekord używamy HibernateDaoTemplate

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

Konfiguracja Wiosna za usługę Wywołanie tej metody jest:

<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> 

Rzeczywisty zakleszczenie występuje na jednym z rekordów PurchaseOrderItem ładowanych przez wywołanie do obciążenia PurchaseOrder.

Czy spowodowałoby to zakleszczenie, jeśli ładowany rekord został zablokowany przez inny proces? A jeśli tak - czy dodanie opakowania transakcji, takiego jak poniżej, rozwiązałoby problem?

<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> 

Aktualizacja: Zespół DataBase odnotowano śladowe wiadomości na serwerze, które wydają się wskazywać, że nasz „tylko do odczytu” proces jest faktycznie automatycznie piśmie do bazy danych. Są zarejestrowane polecenia "UPDATE", które są wykonywane na dokładnych kolumnach, które odczytujemy z bazy danych. Wygląda na to, że Hibernate automatycznie zapisuje te rekordy z powrotem do bazy danych (nawet jeśli nie prosimy o to). To prawdopodobnie tłumaczyłoby, dlaczego istnieje impas.

Czy przyczyną może być SUMA PŁUKANIA lub coś podobnego? Wygląda bardziej na to, że rozwiązaniem może być wykorzystanie opakowania transakcji z readOnly na nim ...

Odpowiedz

1

Ostatecznie ustaliliśmy, że rozwiązaniem jest zawrzeć je w transakcji ReadOnly.

Nie wiem, dlaczego, w ogóle nie używaliśmy seterów (po prostu czytając dane) - nic się nie zmieniło w bazie danych. Ale z jakiegoś powodu Hibernate próbował ponownie zapisać te same dane i powodował blokadę, gdy inny proces próbował odczytać te rekordy.

Korzystanie z transakcji ReadOnly spowodowało, że problem zniknął!

<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

Czy sprawdziłeś, czy w bazie danych nie ma żadnych wyzwalaczy? Czy na pewno jest to Hibernate, a nie jakiś inny proces aktualizujący te same wiersze? Może jest kolumna przechowująca znacznik czasu ostatniego odczytu i jest aktualizowana za każdym razem, gdy czytany jest wiersz (chociaż nie pamiętam, żebyś mógł wywołać wyzwalacze SELECT) ...

2

Mimowolne aktualizacje mogą się zdarzyć ze stanem hibernacji, gdy używasz ustawiających, które manipulują ustawianą wartością. Przykładem może być ustawnik dla atrybutu String, który zastępuje wartość null przez "". Prawdopodobnym kandydatem są również kolekcje. Upewnij się, że setery nie zastępują zawartej kolekcji. Jeśli zamienisz kolekcję obiektu na inny zbiór zawierający tę samą zawartość, hibernacja nie będzie w stanie tego zrealizować i zaktualizować pełną kolekcję.

+0

To nie jest dokładnie to, co się działo - ale wydawało się podobne. Wartości nie zostały "ustawione" w kodzie. Hibernate próbował z jakiegoś powodu przywrócić te same dane (dane w DB nigdy nie zostały zaktualizowane do różnych wartości). – jonathanq

0

Jens ma rację

Aby dodać on- trzeba ściśle kontrolować swoje ustawiające i pobierające i zobaczyć, czy wrócą inną wartość na różnych połączeń np new Date() - to wróci każdy nowy value- Czas jego wywołania i spowoduje hibernację, że obiekt się zmienił.

0

Jedno interesujący zrobić, to dodać

log4j.logger.org.hibernate.persister.entity.AbstractEntityPersister = śladowych

w konfiguracji log4j. Dzięki temu hibernacja będzie rejestrować, dlaczego jednostka potrzebuje aktualizacji w bazie danych. Mieliśmy pewne problemy z obiektami zwracającymi "", gdy właściwość miała wartość zerową, co powodowało aktualizacje w DB. W ten sposób byliśmy w stanie wskazać takie problemy.

0

Widziałem ten problem w naszym systemie, gdy brakowało nam indeksów. Kwerendy wykonywane w bazie danych są zbyt długie z powodu brakujących indeksów w kolumnach kluczy, co blokuje tabelę.