1

Spring 4.0.0、Hibernate 4.2.8、および Ms SQL Server 8 を使用してアプリを開発しています。これは、DB テーブルでサポートされ、Hibernate VO (CustomSequence) でマップされたカスタム シーケンスを使用します。

このシーケンスは、サービス コール内でアクセスされます。

  • メイン サービスが独自のトランザクションを開始する
  • コードを実行し、何かを実行し、クエリを実行します...
  • シーケンス値のシーケンス サービスを呼び出します (SequenceService)

  • SequenceService が独自のトランザクションを開始する (REQUIRES_NEW)

  • SequenceService はオブジェクトを見つけ、値を返し、次の値を保存します

  • メイン サービスは値を取得し、ビジネス オブジェクトに設定して保存します (この時点で、シーケンス値は内部の新しいトランザクションによって既にコミットされています)。

  • 出口

カスタム シーケンスを管理するサービスのスニペット:

@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();
...

私たちの春の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

何が起こっているかの手がかりはありますか? 私はインターネットで多くの情報を読みましたが、役に立ちませんでした

よろしくお願いします!

4

1 に答える 1

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) ...

これは、次の場合にのみカスタム分離レベルを適用できることを意味します: トランザクション マネージャーでそのフラグが有効になっていて、同じデータベース接続が同じ休止状態セッションに常に使用されることが保証されている場合。

そうでない場合、トランザクション マネージャーは分離設定を変更しません。これは、セッションが異なるクエリに対して複数のセッションを使用できる場合、トランザクション マネージャーはセッションがいつプールに送り返されているかを認識できないためです。

これは基本的に、セッションがプールに送信される前に同じ設定をクリーンアップできるという保証がある場合にのみ、トランザクション マネージャーがデータベース セッションの分離設定を変更することを意味します。

于 2014-03-07T10:38:02.330 に答える