有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何在Spring中设置快照隔离级别

谁能帮助我理解如何在Spring的XML配置中将隔离级别设置为SNAPSHOT

我接管了一个以前由别人开发的项目,在某些情况下,我们在使用数据库时会遇到死锁。我已经验证过,尽管数据库隔离级别为SNAPSHOT,但当应用程序发出请求时,该事务的隔离级别将更改为READ_COMMITTED。根据我的简短研究,如果没有明确设置,hibernate使用DEFAULT隔离,对于SQLServer2012来说,它是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_COMMITTEDREPEATABLE_READ,和SERIALIZABLE

在我所拥有的配置的上下文中,是否有一种经过验证的方法将隔离级别设置为SNAPSHOT(或4096

谢谢


共 (1) 个答案

  1. # 1 楼答案

    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>