如何在 Spring 中设置 SNAPSHOT 隔离级别
How to set the SNAPSHOT isolation level in Spring
谁能帮助我了解如何在 Spring 的 XML 配置中将隔离级别设置为 SNAPSHOT
?
我正在接手一个以前由其他人开发的项目,在某些情况下,我们在使用数据库时会遇到死锁。我已经验证,尽管数据库隔离级别为 SNAPSHOT
,但当应用程序发出请求时,该事务的隔离级别更改为 READ_COMMITTED
。根据我的简要研究,如果没有明确设置,hibernate 使用 DEFAULT
隔离,对于 SQLServer 2012 是 READ_COMMITTED
.
不幸的是,我不是 Spring 或 Hibernate 方面的专家,所以我只提供看起来相关的配置:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/ds</value>
</property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list>
...
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${nn.hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${nn.hibernate.showSQL}</prop>
<prop key="hibernate.generate_statistics">${nn.hibernate.generatestatics}</prop>
<prop key="hibernate.hbm2ddl.auto">${nn.hibernate.hbm2ddl}</prop>
<prop key="hibernate.jdbc.batch_size">${nn.hibernate.batchsize}</prop>
<prop key="hibernate.cache.provider_class">${nn.hibernate.cache.provider_class}</prop>
<prop key="hibernate.cache.use_second_level_cache">${nn.hibernate.cache.use_second_level_cache}</prop>
</props>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="save*" read-only="false" rollback-for="NNDBException"/>
<tx:method name="update*" read-only="false" rollback-for="NNDBException"/>
<tx:method name="checkFor*" read-only="false" rollback-for="NNDBException"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
在研究可能的解决方案时,我还了解到在提供 DataSource
时设置 hibernate.connection.isolation
是无效的。
从那里我到达 this example,其中 IsolationLevelDataSourceAdapter
用于在 Connection
的每个实例上设置隔离级别。配置变成了这样:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/ds</value>
</property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<bean class="org.springframework.jdbc.datasource.IsolationLevelDataSourceAdapter">
<property name="targetDataSource" ref="dataSource"/>
<property name="isolationLevel" value="4096" />
</bean>
</property>
<property name="mappingResources">
<list>
...
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${nn.hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${nn.hibernate.showSQL}</prop>
<prop key="hibernate.generate_statistics">${nn.hibernate.generatestatics}</prop>
<prop key="hibernate.hbm2ddl.auto">${nn.hibernate.hbm2ddl}</prop>
<prop key="hibernate.jdbc.batch_size">${nn.hibernate.batchsize}</prop>
<prop key="hibernate.cache.provider_class">${nn.hibernate.cache.provider_class}</prop>
<prop key="hibernate.cache.use_second_level_cache">${nn.hibernate.cache.use_second_level_cache}</prop>
</props>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
<property name="allowCustomIsolationLevels" value="true" />
</bean>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="save*" read-only="false" rollback-for="NNDBException"/>
<tx:method name="update*" read-only="false" rollback-for="NNDBException"/>
<tx:method name="checkFor*" read-only="false" rollback-for="NNDBException"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
我在 sessionFactory
中将隔离级别设置为 4096
。然而,这是我碰壁的地方:IllegalArgumentException: Only isolation constants allowed
,我认为是 DEFAULT
、READ_UNCOMMITTED
、READ_COMMITTED
、REPEATABLE_READ
和 SERIALIZABLE
.
在我拥有的配置上下文中,是否有一种行之有效的方法可以将隔离级别设置为 SNAPSHOT
(或 4096
)?
谢谢。
IsolationLevelDataSourceAdapter
检查标准隔离级别代码,这是一个明显的限制(我建议您为此提交一个 Spring JIRA 问题)。
要解决它,您需要扩展 IsolationLevelDataSourceAdapter
class:
public class CustomIsolationLevelDataSourceAdapter extends IsolationLevelDataSourceAdapter {
private final Integer customIsolationLevel;
public CustomIsolationLevelDataSourceAdapter(Integer customIsolationLevel) {
this.customIsolationLevel = customIsolationLevel;
}
@Override
protected Integer getIsolationLevel() {
return customIsolationLevel != null ? customIsolationLevel : super.getIsolationLevel();
}
}
并使用此 dataSource
代替:
<bean class="my.package.CustomIsolationLevelDataSourceAdapter">
<constructor-arg value="4096"/>
</bean>
谁能帮助我了解如何在 Spring 的 XML 配置中将隔离级别设置为 SNAPSHOT
?
我正在接手一个以前由其他人开发的项目,在某些情况下,我们在使用数据库时会遇到死锁。我已经验证,尽管数据库隔离级别为 SNAPSHOT
,但当应用程序发出请求时,该事务的隔离级别更改为 READ_COMMITTED
。根据我的简要研究,如果没有明确设置,hibernate 使用 DEFAULT
隔离,对于 SQLServer 2012 是 READ_COMMITTED
.
不幸的是,我不是 Spring 或 Hibernate 方面的专家,所以我只提供看起来相关的配置:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/ds</value>
</property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list>
...
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${nn.hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${nn.hibernate.showSQL}</prop>
<prop key="hibernate.generate_statistics">${nn.hibernate.generatestatics}</prop>
<prop key="hibernate.hbm2ddl.auto">${nn.hibernate.hbm2ddl}</prop>
<prop key="hibernate.jdbc.batch_size">${nn.hibernate.batchsize}</prop>
<prop key="hibernate.cache.provider_class">${nn.hibernate.cache.provider_class}</prop>
<prop key="hibernate.cache.use_second_level_cache">${nn.hibernate.cache.use_second_level_cache}</prop>
</props>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="save*" read-only="false" rollback-for="NNDBException"/>
<tx:method name="update*" read-only="false" rollback-for="NNDBException"/>
<tx:method name="checkFor*" read-only="false" rollback-for="NNDBException"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
在研究可能的解决方案时,我还了解到在提供 DataSource
时设置 hibernate.connection.isolation
是无效的。
从那里我到达 this example,其中 IsolationLevelDataSourceAdapter
用于在 Connection
的每个实例上设置隔离级别。配置变成了这样:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/ds</value>
</property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<bean class="org.springframework.jdbc.datasource.IsolationLevelDataSourceAdapter">
<property name="targetDataSource" ref="dataSource"/>
<property name="isolationLevel" value="4096" />
</bean>
</property>
<property name="mappingResources">
<list>
...
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${nn.hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${nn.hibernate.showSQL}</prop>
<prop key="hibernate.generate_statistics">${nn.hibernate.generatestatics}</prop>
<prop key="hibernate.hbm2ddl.auto">${nn.hibernate.hbm2ddl}</prop>
<prop key="hibernate.jdbc.batch_size">${nn.hibernate.batchsize}</prop>
<prop key="hibernate.cache.provider_class">${nn.hibernate.cache.provider_class}</prop>
<prop key="hibernate.cache.use_second_level_cache">${nn.hibernate.cache.use_second_level_cache}</prop>
</props>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
<property name="allowCustomIsolationLevels" value="true" />
</bean>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="save*" read-only="false" rollback-for="NNDBException"/>
<tx:method name="update*" read-only="false" rollback-for="NNDBException"/>
<tx:method name="checkFor*" read-only="false" rollback-for="NNDBException"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
我在 sessionFactory
中将隔离级别设置为 4096
。然而,这是我碰壁的地方:IllegalArgumentException: Only isolation constants allowed
,我认为是 DEFAULT
、READ_UNCOMMITTED
、READ_COMMITTED
、REPEATABLE_READ
和 SERIALIZABLE
.
在我拥有的配置上下文中,是否有一种行之有效的方法可以将隔离级别设置为 SNAPSHOT
(或 4096
)?
谢谢。
IsolationLevelDataSourceAdapter
检查标准隔离级别代码,这是一个明显的限制(我建议您为此提交一个 Spring JIRA 问题)。
要解决它,您需要扩展 IsolationLevelDataSourceAdapter
class:
public class CustomIsolationLevelDataSourceAdapter extends IsolationLevelDataSourceAdapter {
private final Integer customIsolationLevel;
public CustomIsolationLevelDataSourceAdapter(Integer customIsolationLevel) {
this.customIsolationLevel = customIsolationLevel;
}
@Override
protected Integer getIsolationLevel() {
return customIsolationLevel != null ? customIsolationLevel : super.getIsolationLevel();
}
}
并使用此 dataSource
代替:
<bean class="my.package.CustomIsolationLevelDataSourceAdapter">
<constructor-arg value="4096"/>
</bean>