Подтвердить что ты не робот

Спящий режим, spring, JPS и изоляция - пользовательская изоляция не поддерживается

Я пробовал это:

@Transactional(isolation=Isolation.SERIALIZABLE, 
               rollbackFor={Exception.class}, 
               propagation=Propagation.REQUIRES_NEW)

в моих методах обслуживания, но spring жалуется на высказывание:

Standard JPA does not support custom isolation levels - use a special JpaDialect

Как я могу это решить?

4b9b3361

Ответ 2

Никакие пользовательские уровни изоляции не поддерживаются JPA. Вы можете расширить класс HibernateJpaDialect и переопределить связанные с подключением методы, чтобы вы могли устанавливать пользовательские уровни изоляции на Connection

Здесь что-то, что я написал, но еще не проверил:

public class HibernateExtendedJpaDialect extends HibernateJpaDialect {

    @Override
    public Object beginTransaction(EntityManager entityManager,
            TransactionDefinition definition) throws PersistenceException,
            SQLException, TransactionException {

        Session session = (Session) entityManager.getDelegate();
        DataSourceUtils.prepareConnectionForTransaction(session.connection(), definition);

        entityManager.getTransaction().begin();

        return prepareTransaction(entityManager, definition.isReadOnly(), definition.getName());
    }

}

И вы определяете это как свойство своего EntityManagerFactory:

<property name="jpaDialect">
    <bean class="com.company.util.HibernateExtendedJpaDialect" />
</property>

Ответ 3

Опираясь на ответ Божо и рассматривая комментарии к ним, представляется, что это полное (совместимое с Hibernate 4) решение, обращаясь к необходимости reset соединения. Лучше всего сказать, что уровень spring гарантирует вызов метода cleanupTransaction, но если это фактически не гарантировано, возможно, это необходимо передумать из-за возможности утечки памяти PermGen и побочных эффектов после запроса на объект соединения.

public class HibernateExtendedJpaDialect extends HibernateJpaDialect {

  ThreadLocal<Connection> connectionThreadLocal = new ThreadLocal<>();
  ThreadLocal<Integer> originalIsolation = new ThreadLocal<>();

  @Override
  public Object beginTransaction(EntityManager entityManager,
                                 TransactionDefinition definition) 
      throws PersistenceException, SQLException, TransactionException {

    boolean readOnly = definition.isReadOnly();
    Connection connection = 
        this.getJdbcConnection(entityManager, readOnly).getConnection();
    connectionThreadLocal.set(connection);
    originalIsolation.set(DataSourceUtils
        .prepareConnectionForTransaction(connection, definition));

    entityManager.getTransaction().begin();

    return prepareTransaction(entityManager, readOnly, definition.getName());
  }

  /*

   We just have to trust that spring won't forget to call us. If they forget,
   we get a thread-local/classloader memory leak and messed up isolation 
   levels. The finally blocks on line 805 and 876 of 
   AbstractPlatformTransactionManager (Spring 3.2.3) seem to ensure this, 
   though there is a bit of logic between there and the actual call to this 
   method.

   */
  @Override
  public void cleanupTransaction(Object transactionData) {
    try {
      super.cleanupTransaction(transactionData);
      DataSourceUtils.resetConnectionAfterTransaction(
          connectionThreadLocal.get(), originalIsolation.get());
    } finally {
      connectionThreadLocal.remove();
      originalIsolation.remove();
    }
  }
}

Ответ 4

@Shahzad Mughal Я оставил вам две точки;-) Ваш ответ должен быть принят как правильный. Принятый ответ возникнет в следующем выпуске, случайно не позволяющем ведущим разработчикам думать, что есть ошибки с драйвером mysql, например:

WARN [org.hibernate.util.JDBCExceptionReporter] - Ошибка SQL: 0, SQLState: S1009 ERROR [org.hibernate.util.JDBCExceptionReporter] - Соединение доступно только для чтения. Запросы, приводящие к модификации данных, не допускается

Вы можете узнать больше о нашем приключении с этой проблемой в http://thinkinginsoftware.blogspot.com/2013/10/connection-is-read-only-queries-leading.html

Ответ 6

Вы также можете обернуть "datasource" bean с помощью "IsolationLevelDataSourceAdapter", просто сделав следующее:

<bean id="dataSource" class="org.springframework.jdbc.datasource.IsolationLevelDataSourceAdapter">
    <property name="isolationLevelName" value="ISOLATION_READ_COMMITTED"/>
    <property name="targetDataSource" ref="_dataSource"/>
</bean>

где "_dataSource" является ссылкой на фактический источник данных.