복붙노트

[SPRING] Java / Hibernate - 쓰기 작업은 읽기 전용 모드에서 허용되지 않습니다.

SPRING

Java / Hibernate - 쓰기 작업은 읽기 전용 모드에서 허용되지 않습니다.

나는 최근에 성가신 예외를 많이 겪어 왔으며 Google과이 포럼에 대한 연구를 통해 여전히 내 문제를 해결할 수있는 대답을 찾지 못했습니다.

여기에 - 때로는 최대 절전 모드로 새 객체를 업데이트하거나 만들 때 다음과 같은 오류가 발생합니다.

org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.
at org.springframework.orm.hibernate3.HibernateTemplate.checkWriteOperationAllowed(HibernateTemplate.java:1186)
at org.springframework.orm.hibernate3.HibernateTemplate$12.doInHibernate(HibernateTemplate.java:696)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:419)
at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)
at org.springframework.orm.hibernate3.HibernateTemplate.save(HibernateTemplate.java:694)

실제로 이상한 점은 때로 getHibernateTemplate () 메소드로 객체를 업데이트 할 때입니다. saveOrUpdate (object); 그것은 작동하지만, 때로는 같은 객체를 사용하고 동일한 메소드를 호출하면 작동하지 않지만, 처음 객체를 얻는 방법에 의존하는 것처럼 보입니다.

예 : id, type, length의 3 개 필드가있는 테이블이 있다고 가정 해 보겠습니다. 무슨 일이 일어날 수 있습니다, 만약 내가 ID로 개체를 얻고 길이를 업데이 트하면, 그것은 작동합니다. 유형별로 구하고 길이를 업데이트하면 작동하지 않습니다. 그래서 지금까지 문제를 피하기 위해 내가 해왔 던 것은 나중에 문제를 일으키지 않는 메소드를 가져 오는 것입니다. 그러나 이것은 작동하는 방법을 찾기 위해 점점 더 짜증이 날 것입니다.

또한, 지금은이 예외가 개체를 만들려고 할 때 (그러나 모두 하나의 특정 테이블에만있는 경우), 해결 방법을 찾을 수 없습니다. 그리고 트랜잭션에서 @Transactional (readOnly = false)을 추가하려고 시도했지만 아무 것도 변경하지 않았고 모드를 표시하는 것은 어쨌든 읽기 전용 상태가 아니라고 말하고있었습니다.

어떤 제안?

7 월 26 일 수정 : 최대 절전 모드와 관련된 몇 가지 구성이 있습니다.

<property name="hibernateProperties">
    <props>
        <prop key="jdbc.fetch_size">20</prop>
        <prop key="jdbc.batch_size">25</prop>
        <prop key="cglib.use_reflection_optimizer">true</prop>
        <prop key="hibernate.show_sql">true</prop>
        <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
        <prop key="connection.autoReconnect">true</prop>
        <prop key="connection.autoReconnectForPools">true</prop>
        <prop key="connection.is-connection-validation-required">true</prop>
    </props>
</property>

도움이 될 수도 있다면

<property name="transactionAttributes">
    <props>
        <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
        <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
        <prop key="execute*">PROPAGATION_REQUIRED</prop>
        <prop key="add*">PROPAGATION_REQUIRED</prop>
        <prop key="create*">PROPAGATION_REQUIRED</prop>
        <prop key="update*">PROPAGATION_REQUIRED</prop>
        <prop key="delete*">PROPAGATION_REQUIRED</prop>
    </props>
</property>

8 월 31 일 수정 : 객체를 저장하기 위해 HibernateDaoSupport를 확장하는 클래스의 관련 코드는 다음과 같습니다.

public void createObject(Object persisObj) {
    getHibernateTemplate().save(persisObj);
}

해결법

  1. ==============================

    1.뷰 필터에서 단일 세션 속성을 변경했습니다. 문제 해결됨:

    뷰 필터에서 단일 세션 속성을 변경했습니다. 문제 해결됨:

      <filter>
        <filter-name>hibernateFilter</filter-name>
        <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
        <init-param>
          <param-name>singleSession</param-name>
          <param-value>false</param-value>
        </init-param>
      </filter>
    
  2. ==============================

    2.이 오류 메시지는 일반적으로 Spring OpenSessionInViewFilter를 사용하고 Spring 관리 트랜잭션 외부에서 지속성 작업을 수행하려고 할 때 나타납니다. 필터는 세션을 FlushMode.NEVER / MANUAL로 설정합니다 (사용중인 Spring 및 Hibernate의 버전에 따라 다름 - 대략 동일합니다). Spring 트랜잭션 메커니즘이 트랜잭션을 시작할 때, 플러시 모드를 "COMMIT"으로 변경한다. 트랜잭션이 완료되면 필요에 따라 NEVER / MANUAL로 다시 설정합니다. 이것이 일어나지 않는다고 확신하는 경우, 다음으로 가장 큰 원인은 세션을 스레드로부터 안전하게 사용할 수 없다는 것입니다. Hibernate Session은 하나의 쓰레드에서만 사용되어야한다. 그것이 쓰레드 사이를 넘으면 모든 종류의 혼돈이 일어날 수 있습니다. Hibernate에서로드 된 엔티티는로드 된 Session에 대한 참조를 보유 할 수 있으며 스레드를 통해 엔티티를 전달하면 다른 스레드에서도 Session에 액세스 할 수 있습니다.

    이 오류 메시지는 일반적으로 Spring OpenSessionInViewFilter를 사용하고 Spring 관리 트랜잭션 외부에서 지속성 작업을 수행하려고 할 때 나타납니다. 필터는 세션을 FlushMode.NEVER / MANUAL로 설정합니다 (사용중인 Spring 및 Hibernate의 버전에 따라 다름 - 대략 동일합니다). Spring 트랜잭션 메커니즘이 트랜잭션을 시작할 때, 플러시 모드를 "COMMIT"으로 변경한다. 트랜잭션이 완료되면 필요에 따라 NEVER / MANUAL로 다시 설정합니다. 이것이 일어나지 않는다고 확신하는 경우, 다음으로 가장 큰 원인은 세션을 스레드로부터 안전하게 사용할 수 없다는 것입니다. Hibernate Session은 하나의 쓰레드에서만 사용되어야한다. 그것이 쓰레드 사이를 넘으면 모든 종류의 혼돈이 일어날 수 있습니다. Hibernate에서로드 된 엔티티는로드 된 Session에 대한 참조를 보유 할 수 있으며 스레드를 통해 엔티티를 전달하면 다른 스레드에서도 Session에 액세스 할 수 있습니다.

  3. ==============================

    3.나는 이것에 너무 비틀 거리다. Spring의 OpenSessionInViewFilter에서 플러시 모드를 수동으로 변경해야하고 갑자기이 예외가 발생하기 시작했습니다. @Transactional로 주석 처리되지 않은 메소드에서 문제가 발생했다는 것을 알게되었으므로 Spring은 이러한 메소드 외부의 모든 데이터 액세스 코드를 암시 적으로 읽기 전용으로 취급한다고 생각합니다. 이 방법에 주석을 달면 문제가 해결됩니다.

    나는 이것에 너무 비틀 거리다. Spring의 OpenSessionInViewFilter에서 플러시 모드를 수동으로 변경해야하고 갑자기이 예외가 발생하기 시작했습니다. @Transactional로 주석 처리되지 않은 메소드에서 문제가 발생했다는 것을 알게되었으므로 Spring은 이러한 메소드 외부의 모든 데이터 액세스 코드를 암시 적으로 읽기 전용으로 취급한다고 생각합니다. 이 방법에 주석을 달면 문제가 해결됩니다.

    또 다른 방법은 HibernateTemplate 객체에서 setCheckWriteOperations 메소드를 호출하는 것이다.

  4. ==============================

    4.더하다

    더하다

    @Transactional
    

    당신의 기능 위에

  5. ==============================

    5.응용 프로그램 컨텍스트에서 HibernateTemplate에 대해 아래 Bean을 사용하십시오.

    응용 프로그램 컨텍스트에서 HibernateTemplate에 대해 아래 Bean을 사용하십시오.

    <bean id="template" class="org.springframework.orm.hibernate4.HibernateTemplate">  
            <property name="sessionFactory" ref="mysessionFactory"></property>
            <property name="checkWriteOperations" value="false"></property>
            </bean>
    
  6. ==============================

    6.이것을 사용해보십시오.

    이것을 사용해보십시오.

    hibernateTemplate = new HibernateTemplate(sessionFactory);
    hibernateTemplate.setCheckWriteOperations(false);
    

    트랜잭션을 사용하고 있는지 여부를 템플릿에서 확인하지 않으므로 오류가 사라집니다.

  7. ==============================

    7.@Transactional 어노테이션을 DAO 서비스 클래스 / 메소드에 추가하는 것을 잊었어야합니다. 그러면 데이터베이스 관리 작업이 스프링 관리 트랜잭션에 의해 처리되도록 지정됩니다.

    @Transactional 어노테이션을 DAO 서비스 클래스 / 메소드에 추가하는 것을 잊었어야합니다. 그러면 데이터베이스 관리 작업이 스프링 관리 트랜잭션에 의해 처리되도록 지정됩니다.

  8. ==============================

    8.아래 코드는 저에게 도움이됩니다.

    아래 코드는 저에게 도움이됩니다.

    hibernateTemplate = new HibernateTemplate(sessionFactory);
    hibernateTemplate.setCheckWriteOperations(false);
    
  9. ==============================

    9.1) @Transactional을 데이터베이스 조작 메소드 위에 추가하고 2) 주석 관리 전환 관리자가 있어야합니다.

    1) @Transactional을 데이터베이스 조작 메소드 위에 추가하고 2) 주석 관리 전환 관리자가 있어야합니다.

    더하다

    applicationContext.xml 파일의 HibernateTransactionManager 설정 위

  10. ==============================

    10.나는 같은 문제를 겪었고 어느 ​​날 수사가 끝나자 나는 다음 선언을 관찰했다.

    나는 같은 문제를 겪었고 어느 ​​날 수사가 끝나자 나는 다음 선언을 관찰했다.

    <tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
    

    나는 지웠다

    mode="aspectj"
    

    그 문제는 사라졌다.

  11. from https://stackoverflow.com/questions/6810158/java-hibernate-write-operations-are-not-allowed-in-read-only-mode by cc-by-sa and MIT license