1. 程式人生 > >對於Hibernate的openSession方法為什麼不是執行緒安全的原始碼理解

對於Hibernate的openSession方法為什麼不是執行緒安全的原始碼理解

首先,先明確幾個概念。

1、區域性變數不會受多執行緒影響。

2、成員變數會受到多執行緒影響。
多個執行緒呼叫的同一個物件的同一個方法:
如果方法裡無成員變數,不受任何影響,
如果方法裡有成員變數,只有讀操作,不受影響,存在賦值操作,有影響。

第一點
SessionFactory和Session都是介面,SessionFactoryImpl和SessionImpl是其實現。

第二點
SessionFactoryImpl裡的openSession方法如下,其中的 new SessionImpl(…)存線上程不安全的因素。

    @Override
        public
Session openSession() { log.tracef( "Opening Hibernate Session. tenant=%s, owner=%s", tenantIdentifier, sessionOwner ); final SessionImpl session = new SessionImpl( connection, sessionFactory, sessionOwner, getTransactionCoordinator(), autoJoinTransactions, sessionFactory.settings.getRegionFactory().nextTimestamp(), interceptor, flushBeforeCompletion, autoClose, connectionReleaseMode, tenantIdentifier ); for
( SessionEventListener listener : listeners ) { session.getEventListenerManager().addListener( listener ); } return session; }

第三點
通過觀察下面SessionImpl的原始碼實現,可以發現在構造方法內部出現了對於成員變數的賦值的操作,所以執行緒不安全。

    SessionImpl(
            final Connection connection,
            final
SessionFactoryImpl factory, final SessionOwner sessionOwner, final TransactionCoordinatorImpl transactionCoordinator, final boolean autoJoinTransactions, final long timestamp, final Interceptor interceptor, final boolean flushBeforeCompletionEnabled, final boolean autoCloseSessionEnabled, final ConnectionReleaseMode connectionReleaseMode, final String tenantIdentifier) { super( factory, tenantIdentifier ); this.timestamp = timestamp; this.sessionOwner = sessionOwner; this.interceptor = interceptor == null ? EmptyInterceptor.INSTANCE : interceptor; this.actionQueue = new ActionQueue( this ); this.persistenceContext = new StatefulPersistenceContext( this ); this.autoCloseSessionEnabled = autoCloseSessionEnabled; this.flushBeforeCompletionEnabled = flushBeforeCompletionEnabled; if ( transactionCoordinator == null ) { this.isTransactionCoordinatorShared = false; this.connectionReleaseMode = connectionReleaseMode; this.autoJoinTransactions = autoJoinTransactions; this.transactionCoordinator = new TransactionCoordinatorImpl( connection, this ); this.transactionCoordinator.getJdbcCoordinator().getLogicalConnection().addObserver( new ConnectionObserverStatsBridge( factory ) ); } else { if ( connection != null ) { throw new SessionException( "Cannot simultaneously share transaction context and specify connection" ); } this.transactionCoordinator = transactionCoordinator; this.isTransactionCoordinatorShared = true; this.autoJoinTransactions = false; if ( autoJoinTransactions ) { LOG.debug( "Session creation specified 'autoJoinTransactions', which is invalid in conjunction " + "with sharing JDBC connection between sessions; ignoring" ); } if ( connectionReleaseMode != transactionCoordinator.getJdbcCoordinator().getLogicalConnection().getConnectionReleaseMode() ) { LOG.debug( "Session creation specified 'connectionReleaseMode', which is invalid in conjunction " + "with sharing JDBC connection between sessions; ignoring" ); } this.connectionReleaseMode = transactionCoordinator.getJdbcCoordinator().getLogicalConnection().getConnectionReleaseMode(); // add a transaction observer so that we can handle delegating managed actions back to THIS session // versus the session that created (and therefore "owns") the transaction coordinator transactionObserver = new TransactionObserver() { @Override public void afterBegin(TransactionImplementor transaction) { } @Override public void beforeCompletion(TransactionImplementor transaction) { if ( isOpen() && flushBeforeCompletionEnabled ) { SessionImpl.this.managedFlush(); } beforeTransactionCompletion( transaction ); } @Override public void afterCompletion(boolean successful, TransactionImplementor transaction) { afterTransactionCompletion( transaction, successful ); if ( isOpen() && autoCloseSessionEnabled ) { managedClose(); } transactionCoordinator.removeObserver( this ); } }; transactionCoordinator.addObserver( transactionObserver ); } loadQueryInfluencers = new LoadQueryInfluencers( factory ); if (factory.getStatistics().isStatisticsEnabled()) { factory.getStatisticsImplementor().openSession(); } if ( TRACE_ENABLED ) LOG.tracef( "Opened session at timestamp: %s", timestamp ); }

當然,這些只是博主粗淺的理解。