java Hibernate、spring、JPS 和隔离 - 不支持自定义隔离
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5234240/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Hibernate, spring, JPS & isolation - custom isolation not supported
提问by Ikthiander
I have been trying this:
我一直在尝试这个:
@Transactional(isolation=Isolation.SERIALIZABLE,
rollbackFor={Exception.class},
propagation=Propagation.REQUIRES_NEW)
on my service methods, but spring complains saying:
在我的服务方法上,但 spring 抱怨说:
Standard JPA does not support custom isolation levels - use a special JpaDialect
How can I resolve this?
我该如何解决这个问题?
采纳答案by Shahzad Mughal
This implementation is not account for the clean up stuff, I have implemented a similar solution but that accounts for the clean up as well. That solution can be found here: http://shahzad-mughal.blogspot.com/2012/04/spring-jpa-hibernate-support-for-custom.html
这个实现不考虑清理的东西,我已经实现了一个类似的解决方案,但这也考虑了清理。该解决方案可以在这里找到:http: //shahzad-mughal.blogspot.com/2012/04/spring-jpa-hibernate-support-for-custom.html
回答by Bozho
No custom isolation levels are supported by JPA. You can extend the HibernateJpaDialect
class and override connection-related methods so that you can set custom isolation levels on the Connection
JPA 不支持自定义隔离级别。您可以扩展HibernateJpaDialect
该类并覆盖与连接相关的方法,以便您可以在Connection
Here's something that I've written, but have not tested yet:
这是我写的东西,但还没有测试:
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());
}
}
And you define this as a property of your EntityManagerFactory
:
您将其定义为您的属性EntityManagerFactory
:
<property name="jpaDialect">
<bean class="com.company.util.HibernateExtendedJpaDialect" />
</property>
回答by Gus
Drawing on Bozho's answer and considering the comments thereon, The following seems to be a complete (Hibernate 4 compatible) solution addressing the need reset the connection. Best I can tell, the spring layer will guarantee call the cleanupTransaction method, but if that isn't actually guaranteed, this may need to be re-thought due to the potential for a permGen memory leak and post request side effects on the connection object.
借鉴 Bozho 的回答并考虑对其的评论,以下似乎是一个完整的(与 Hibernate 4 兼容的)解决方案,解决了重置连接的需要。我能说的最好的是,spring 层将保证调用 cleanupTransaction 方法,但如果实际上不能保证,这可能需要重新考虑,因为 permGen 内存泄漏和 post request 对连接对象的副作用的可能性.
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();
}
}
}
回答by Nestor Urquiza
@Shahzad Mughal I left you two points ;-) Your answer should be accepted as the correct one. The accepted answer will originate the below issue randomly miss leading developers to think there are bugs with mysql driver for example:
@Shahzad Mughal 我给你留下了两点 ;-) 你的答案应该被接受为正确的答案。接受的答案将引发以下问题,随机错过导致开发人员认为 mysql 驱动程序存在错误,例如:
WARN [org.hibernate.util.JDBCExceptionReporter] - SQL Error: 0, SQLState: S1009 ERROR [org.hibernate.util.JDBCExceptionReporter] - Connection is read-only. Queries leading to data modification are not allowed
警告 [org.hibernate.util.JDBCExceptionReporter] - SQL 错误:0,SQLState:S1009 错误 [org.hibernate.util.JDBCExceptionReporter] - 连接是只读的。不允许导致数据修改的查询
You can read more about our adventure with this issue at http://thinkinginsoftware.blogspot.com/2013/10/connection-is-read-only-queries-leading.html
您可以在http://thinkinginsoftware.blogspot.com/2013/10/connection-is-read-only-queries-leading.html阅读更多关于我们在这个问题上的冒险
回答by Robby Pond
When specifying the JpaTransactionManagerdid you specify a JPADialect? By default I think it uses the DefaultJpaDialectand you need the HibernateJpaDialect.
在指定JpaTransactionManager时,您是否指定了 JPADialect?默认情况下,我认为它使用DefaultJpaDialect并且您需要HibernateJpaDialect。
回答by polesen
You can also wrap the "datasource" bean with the "IsolationLevelDataSourceAdapter", by simply doing this:
您还可以使用“IsolationLevelDataSourceAdapter”包装“数据源”bean,只需执行以下操作:
<bean id="dataSource" class="org.springframework.jdbc.datasource.IsolationLevelDataSourceAdapter">
<property name="isolationLevelName" value="ISOLATION_READ_COMMITTED"/>
<property name="targetDataSource" ref="_dataSource"/>
</bean>
where "_dataSource" is a ref to an actual datasource.
其中“_dataSource”是对实际数据源的引用。