2009-03-19 2 views
5

Oracle Deadlock (ORA-00060 : 리소스를 기다리는 동안 교착 상태가 감지되었습니다.) 오류가 발생했습니다. 이 문제는 다른 프로세스가 같은 행에서 업데이트를 수행하는 동안 Hibernate를 사용하여 읽기 전용 연산을 수행하는 프로세스에서 발생한다고 제안되었습니다.Hibernate 응용 프로그램이 읽기 전용으로 데이터를로드 할 때 교착 상태가 발생했습니다.

해당 읽기 전용 프로세스는 최대 절전 모드와 봄 모드를 사용하여 구성됩니다. 우리는 서비스에 대한 트랜잭션을 명시 적으로 정의하지 않았습니다. 그 동안 이상하지 않을 수 있습니다 - 저장/업데이트 작업이 수행되지 않을 때 Hibernate가 행에 독점적 인 잠금을 얻으려고하는 이유를 알지 못합니다 - get/load 만.

제 질문은 : 명시 적 트랜잭션 관리가 정의되어 있지 않을 때 Hibernate는 객체의 "로드"만 수행되는 경우에도 행에 읽기/쓰기 잠금을 시도하려고합니까? 저장/업데이트가 수행되지 않습니다.

데이터를로드하는 서비스를 중심으로 트랜잭션을 정의한 다음 transactionAttributes에 READONLY를 명시하면 Hibernate가 이미 존재하는 행 잠금을 무시하고 읽기 전용으로 데이터를로드 할 수 있습니까? 여기

는 일부 코드의 예입니다 : 우리가 HibernateDaoTemplate을 사용하고있는 기록을로드하기위한

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

이 메서드를 호출 서비스에 대한 봄의 구성은 다음과 같습니다

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

실제에게 PurchaseOrder로드에 대한 호출에 의해로드 된 PurchaseOrderItem 레코드 중 하나에서 교착 상태가 발생합니다.

로드중인 레코드가 다른 프로세스에 의해 잠긴 경우 교착 상태가 발생합니까? 그렇다면 아래의 트랜잭션 래퍼를 추가하면 문제가 해결됩니까?

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

업데이트 : 데이터베이스 팀은 "읽기 전용"프로세스가 실제로 자동으로 데이터베이스에 기록되어 있음을 시사한다 서버에서 추적 메시지를 볼 수있다. 데이터베이스에서 읽는 정확한 열에서 수행되는 "UPDATE"명령이 기록됩니다. Hibernate가 자동적으로이 레코드들을 데이터베이스에 다시 쓰고있는 것처럼 보인다. (우리가 요청하지는 않지만). 그러면 교착 상태가 발생하는 이유를 설명 할 수 있습니다.

세션 플러시 또는 이와 유사한 이유로 인해 발생할 수 있습니까? 솔루션처럼 readOnly를 사용하여 트랜잭션 래퍼를 사용할 수도 있습니다 ...

답변

1

마지막으로 솔루션이 readOnly 트랜잭션으로 래핑하는 것으로 결정했습니다.

왜 우리는 (데이터를 읽는 것만 큼) setter를 사용하지 않았는지 명확하지 않습니다. 데이터베이스에서 아무 것도 변경되지 않았습니다. 그러나 어떤 이유 때문에 Hibernate는 같은 데이터를 다시 쓰려고 시도했고 다른 프로세스가 그 레코드를 읽으려고 할 때 잠금을 일으켰다.

readOnly 트랜잭션을 사용하면 문제가 사라졌습니다!

<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

데이터베이스에서 트리거를 확인 했습니까? 당신은 그것이 Hibernate이고 다른 프로세스가 그 같은 행을 업데이트하지 않는 것이 확실합니까? 어쩌면 마지막으로 읽은 타임 스탬프를 저장하는 열이 있는데 행이 읽힐 때마다 업데이트됩니다 (비록 내가 SELECT 트리거를 만들 수 있다는 것을 기억하지 못하더라도).

2

Involuntary 실제로 설정 한 값을 조작하는 setter를 사용하면 최대 절전 모드로 업데이트가 발생할 수 있습니다. 예를 들어, null 값을 ""로 바꾸는 String 속성의 설정자가 있습니다. 가능성이 큰 후보는 또한 콜렉션입니다. setter가 포함 된 콜렉션을 대체하지 않는지 확인하십시오. 엔티티의 콜렉션을 동일한 컨텐츠를 포함하는 다른 콜렉션으로 대체하면, 최대 절전 모드는이를 인식하지 못하고 전체 콜렉션을 업데이트 할 수 없다.

+0

정확히 무슨 일이 일어나고있는 것은 아니지만 비슷한 것처럼 보입니다. 값은 코드에서 "설정"되지 않았습니다. Hibernate는 실제로 어떤 이유로 DB에있는 데이터가 결코 다른 값으로 업데이트되지 않도록 동일한 데이터를 다시 쓰려고 시도했다. – jonathanq

0

옌스는 밀접하게) 당신의 세터와 게터를 검사하고 그들이 (다른 통화에 예를 들어, 새로운 일을 다른 값을 반환하면 볼 필요가 온

추가 할 수있는 권리입니다 -이 새로운 부가가치를 각각 반환 호출 된 시간과 최대 절전 모드로 객체가 변경되었다고 생각할 것입니다.

0

한 것은 당신의 log4j 구성에

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

를 추가하는 것입니다. 그렇게함으로써 최대 절전 모드는 엔티티가 데이터베이스에서 업데이트가 필요한 이유를 기록 할 것입니다. DB에서 업데이트가 발생하는 속성이 null 인 경우 ""를 반환하는 엔터티에 몇 가지 문제가있었습니다. 그렇게함으로써 우리는 그러한 문제를 정확하게 지적 할 수있었습니다.

0

색인이 누락되었을 때 우리 시스템에서이 문제가 발생하는 것을 보았습니다. 데이터베이스에서 실행중인 쿼리가 키 열의 누락 된 인덱스로 인해 너무 오래 실행되어 테이블을 잠그고 있습니다.