我一直在尝试这个:
@Transactional(isolation=Isolation.SERIALIZABLE,
rollbackFor={Exception.class},
propagation=Propagation.REQUIRES_NEW)
我的服务方法,但春天抱怨说:
Standard JPA does not support custom isolation levels - use a special JpaDialect
我该如何解决这个问题?
答案 0 :(得分:10)
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>
答案 1 :(得分:10)
这个实现不是清理工作的原因,我已经实现了类似的解决方案,但也考虑了清理。 该解决方案可以在这里找到: http://shahzad-mughal.blogspot.com/2012/04/spring-jpa-hibernate-support-for-custom.html
答案 2 :(得分:3)
借鉴Bozho的答案并考虑其上的评论,以下似乎是一个完整的(Hibernate 4兼容)解决方案,解决了重置连接的需要。最好我可以告诉,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();
}
}
}
答案 3 :(得分:0)
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
了解有关此问题的更多信息答案 4 :(得分:-1)
指定JpaTransactionManager时是否指定了JPADialect?默认情况下,我认为它使用的是DefaultJpaDialect,您需要HibernateJpaDialect。
答案 5 :(得分:-1)
您也可以使用“IsolationLevelDataSourceAdapter”封装“datasource”bean,只需执行以下操作:
<bean id="dataSource" class="org.springframework.jdbc.datasource.IsolationLevelDataSourceAdapter">
<property name="isolationLevelName" value="ISOLATION_READ_COMMITTED"/>
<property name="targetDataSource" ref="_dataSource"/>
</bean>
其中“_dataSource”是对实际数据源的引用。