Ответ 1
Эта реализация не учитывает очистку, я реализовал аналогичное решение, но это также объясняет необходимость очистки. Это решение можно найти здесь: http://shahzad-mughal.blogspot.com/2012/04/spring-jpa-hibernate-support-for-custom.html
Я пробовал это:
@Transactional(isolation=Isolation.SERIALIZABLE,
rollbackFor={Exception.class},
propagation=Propagation.REQUIRES_NEW)
в моих методах обслуживания, но spring жалуется на высказывание:
Standard JPA does not support custom isolation levels - use a special JpaDialect
Как я могу это решить?
Эта реализация не учитывает очистку, я реализовал аналогичное решение, но это также объясняет необходимость очистки. Это решение можно найти здесь: http://shahzad-mughal.blogspot.com/2012/04/spring-jpa-hibernate-support-for-custom.html
Никакие пользовательские уровни изоляции не поддерживаются 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>
Опираясь на ответ Божо и рассматривая комментарии к ним, представляется, что это полное (совместимое с 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();
}
}
}
@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
При указании JpaTransactionManager вы указали JPADialect? По умолчанию я думаю, что он использует DefaultJpaDialect, и вам нужно HibernateJpaDialect.
Вы также можете обернуть "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" является ссылкой на фактический источник данных.