java - 如何在 Spring 中设置 SNAPSHOT 隔离级别

标签 java sql-server spring hibernate isolation-level

谁能帮我理解如何在 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,我认为是DEFAULTREAD_UNCOMMITTEDREAD_COMMITTED REPEATABLE_READSERIALIZABLE

在我拥有的配置上下文中,是否有一种行之有效的方法可以将隔离级别设置为 SNAPSHOT(或 4096)?

谢谢。

最佳答案

IsolationLevelDataSourceAdapter 检查标准隔离级别代码,这是一个明显的限制(我建议您为此提交一个 Spring JIRA 问题)。

要解决它,您需要扩展 IsolationLevelDataSourceAdapter 类:

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>

关于java - 如何在 Spring 中设置 SNAPSHOT 隔离级别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31014345/

相关文章:

java - 无法在lucene中搜索实体

SQL Server 2005 DateTime(仅返回 hh :mm)

sql - 如果连接/where 条件中有格式化/转换,索引是否有效?

java - 使用 LiquiBase 和 Spring 将大量值(使用 FK)插入数据库

java - "-Drun.profiles=.."尝试执行 Spring Boot jar 时不起作用

java - Eclipse 中的自定义编译时类加载?

java - 玩! 2.1 更新 Play! 后表格被破坏! 2.0应用程序

java - 未使用的基元数组 : what do javac and the JIT compiler do with it?

将 varchar 值转换为数字数据类型时 SQL 转换失败

java - Hibernate StatelessSession 以及 Oracle 和 SQL Server 上的奇怪行为