2014-03-07 21 views
1

我們正在開發Spring 4.0.0,Hibernate 4.2.8和Ms SQL Server 8的應用程序,該應用程序使用由DB表格支持的自定義序列並使用Hibernate映射VO(CustomSequence)使用Spring 4.0和Hibernate 4.2.8更改隔離級別012.8

這個序列服務呼叫內accesed:

  • 主要服務啓動它自己的事務
  • 執行代碼,做一些事情,查詢...
  • 調用序列服務爲一個序列值(S equenceService)

  • SequenceService開始了自己的交易(REQUIRES_NEW)

  • SequenceService找到對象,返回值並保存下一個值

  • 主要服務獲取價值,將業務對象並保存(在此點序列值已經由內新的事務)

  • 退出COMMITED

片段,其管理自定義序列的服務的:

@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.SERIALIZABLE) 
@Service("sequenceService") 
public class SequenceService implements ISequenceService { 

    @Autowired 
    private ISequenceDao sequenceDao; 

    private Integer getSequence() { 

     CustomSequence sequenceOut = sequenceDao.find(); 

     final Integer nextVal = sequenceOut.getNextVal(); 
     sequenceOut.setNextVal(nextVal + 1); 
     sequenceDao.save(sequenceOut); 

     return nextVal;  
    }  
} 

我們的問題是可序列化的屬性被完全忽略,以便2個併發線程訪問某個getSequence方法,將獲得相同的值。

如果我們檢查與TransactionSynchronizationManager隔離值似乎是正確的序列(值= 8):

... 
Integer isolation = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel(); 
... 

我們的Spring XML文件是這個:

<context:annotation-config /> 
<context:component-scan base-package="dev.app"/> 
<tx:annotation-driven /> 

<bean name="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> 
    <property name="sessionFactory" ref="sessionFactory" /> 
</bean> 

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> 
    <property name="jndiName" value="java:comp/env/jdbc/appDatasource"/> 
</bean>  

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" lazy-init="false" > 
    <property name="dataSource"> <ref bean="dataSource" /></property> 
    <property name="packagesToScan" value="dev.app.model"/> 
    <property name="hibernateProperties"> 
     <props> 
      <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop> 
      <prop key="hibernate.show_sql">true</prop> 
      <prop key="hibernate.format_sql">true</prop> 
      <!-- Disable LOB creation as connection --> 
      <prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop> 
     </props> 
    </property> 
</bean> 

我檢查了數據庫序列化MS SQL Management Studio與這些命令的能力,然後執行應用程序代碼,它的工作(阻止代碼,直到工作室提交):

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 

BEGIN TRAN 

UPDATE CUSTOM_SEQUENCE set NEXTVAL = 1000; 
WAITFOR DELAY '00:1:00' 

COMMIT 

¿發生了什麼事情的線索?我已經閱讀了很多互聯網上的信息,但無濟於事

很多預先致謝!

回答

0

HibernateTransactionManager代碼,這可能是因爲事情是,事務管理的prepareConnection標誌設置爲false:

/** 
* Set whether to prepare the underlying JDBC Connection of a transactional 
* Hibernate Session, that is, whether to apply a transaction-specific 
* isolation level and/or the transaction's read-only flag to the underlying 
* JDBC Connection. 
* <p>Default is "true". If you turn this flag off, the transaction manager 
* will not support per-transaction isolation levels anymore. ... 
*/ 
public void setPrepareConnection(boolean prepareConnection) { 
    this.prepareConnection = prepareConnection; 
} 

嘗試,把一個斷點,看看它的情況。另外這個標誌總是與isSameConnectionForEntireSession(session)一起使用:

if (this.prepareConnection && isSameConnectionForEntireSession(session)) { 
    .... 
} 

isSameConnectionForEntireSession說:

/** 
* Return whether the given Hibernate Session will always hold the same 
* JDBC Connection. This is used to check whether the transaction manager 
* can safely prepare and clean up the JDBC Connection used for a transaction. 
* <p>The default implementation checks the Session's connection release mode 
* to be "on_close". 
*/ 
protected boolean isSameConnectionForEntireSession(Session session) ... 

這意味着,如果一個自定義的隔離級別只能應用於:這樣做標誌的事務管理器啓用並且保證相同的數據庫連接將始終用於相同的休眠會話。

如果不是這種情況,那麼事務管理器不會更改隔離設置,因爲如果會話可以針對不同的查詢使用多個會話,則事務管理器將不知道會話何時被髮送回池。

這基本上意味着事務管理器只會更改數據庫會話的隔離設置,前提是它可以保證在會話發送到池之前可以清除那些相同的設置。

+0

感謝您的回答。我已經調試了這個類,它看起來一切正常,因爲這個標誌並沒有改變(真正的值),並且isSameConnectionForEntireSession(session)的值也是如此。它輸入DataSourceUtils.prepareConnectionForTransaction(con,定義)並將當前隔離設置爲8(以前的隔離爲2)。內部事務結束後,執行恢復以前的隔離值(2)的「doCleanupAfterCompletion」。我只是不知道這裏出了什麼問題。 – pollytronman

+0

我認爲問題與服務器有關。從零開始重新部署在全新的服務器上解決了問題... – pollytronman