前言:
如果大家使用過Spring事務(wù)管理,會發(fā)現(xiàn)Spring提供的事務(wù)分為“只讀”和“讀寫”事務(wù)兩類。這不免就會疑問這兩種事務(wù)會有什么不同?本文則通過對Spring和Hibernate源代碼的剖析來找出這兩種事務(wù)的區(qū)別。特別是運行性能方面的區(qū)別。 解讀的源代碼版本為 Spring 2.5.6.SEC01 ,Hibernate 3.3.2.GA。 Spring對事務(wù)的支持也分編程式和聲明式,本文以基于Annotation方式的聲明式事務(wù)為例: Spring的配置如下: <bean
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"> <property name="proxyTargetClass" value="true"></property> </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="entityManager" /> <property name="jpaProperties"> <props> </props> </property> </bean> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> <property name="transactionManager" ref="transactionManager" /> <property name="transactionAttributeSource"> <bean class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource" /> </property> </bean> <bean id="transactionAttributeSourceAdvisor" class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor"> <property name="transactionInterceptor" ref="transactionInterceptor" /> </bean> 從配置中,可以看到事務(wù)的攔截,都由 TransactionInterceptor 類進行處理 下面是invoke方法的核心處理過程: public Object invoke(final MethodInvocation invocation) throws Throwable {
// Work out the target class: may be <code>null</code>. // The TransactionAttributeSource should be passed the target class // as well as the method, which may be from an interface. Class targetClass = (invocation.getThis() != null ? invocation.getThis().getClass() : null); // If the transaction attribute is null, the method is non-transactional. final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass); final String joinpointIdentification = methodIdentification(invocation.getMethod()); if (txAttr == null || !(getTransactionManager() instanceof CallbackPreferringPlatformTransactionManager)) { // Standard transaction demarcation with getTransaction and commit/rollback calls. TransactionInfo txInfo = createTransactionIfNecessary(txAttr, joinpointIdentification); Object retVal = null; try { // This is an around advice: Invoke the next interceptor in the chain. // This will normally result in a target object being invoked. retVal = invocation.proceed(); } catch (Throwable ex) { // target invocation exception completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { cleanupTransactionInfo(txInfo); } //處理事務(wù)的操作 commitTransactionAfterReturning(txInfo); return retVal; } ![]() } 針對事務(wù)的操作,就是調(diào)用 commitTransactionAfterReturning 方法進行事務(wù)的處理。 該方法會調(diào)用AbstractPlatformTransactionManager類的commit和processCommit方法。processCommit方法是真正調(diào)用Hibernate事務(wù)處理的實現(xiàn)。 private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try { boolean beforeCompletionInvoked = false; try { prepareForCommit(status); triggerBeforeCommit(status); triggerBeforeCompletion(status); beforeCompletionInvoked = true; boolean globalRollbackOnly = false; if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) { globalRollbackOnly = status.isGlobalRollbackOnly(); } if (status.hasSavepoint()) { if (status.isDebug()) { logger.debug("Releasing transaction savepoint"); } status.releaseHeldSavepoint(); } else if (status.isNewTransaction()) { //如果是一個新啟的事務(wù) if (status.isDebug()) { logger.debug("Initiating transaction commit"); }//則進行事務(wù)的提交處理 doCommit(status); } ![]() } doCommit 方法的調(diào)用 會觸發(fā) Hibernate的JDBCTransaction的commit方法調(diào)用 public void commit() throws HibernateException {
if (!begun) { throw new TransactionException("Transaction not successfully started"); } log.debug("commit"); //如果是只讀事務(wù),Spring會將transactionContext的 isFlushModeNever 設(shè)置為true if ( !transactionContext.isFlushModeNever() && callback ) { //刷新一級緩存中的持久對象,向數(shù)據(jù)庫發(fā)送sql語句 transactionContext.managedFlush(); //if an exception occurs during flush, user must call rollback() } notifyLocalSynchsBeforeTransactionCompletion(); if ( callback ) { jdbcContext.beforeTransactionCompletion( this ); } try { commitAndResetAutoCommit(); log.debug("committed JDBC Connection"); committed = true; if ( callback ) { jdbcContext.afterTransactionCompletion( true, this ); } notifyLocalSynchsAfterTransactionCompletion( Status.STATUS_COMMITTED ); } catch (SQLException e) { log.error("JDBC commit failed", e); commitFailed = true; if ( callback ) { jdbcContext.afterTransactionCompletion( false, this ); } notifyLocalSynchsAfterTransactionCompletion( Status.STATUS_UNKNOWN ); throw new TransactionException("JDBC commit failed", e); } finally { closeIfRequired(); } } 關(guān)鍵點已經(jīng)在上面的注釋中說明。 當(dāng)事務(wù)被標(biāo)識為只讀事務(wù)時,Spring可以對某些可以針對只讀事務(wù)進行優(yōu)化的資源就可以執(zhí)行相應(yīng)的優(yōu)化措施,上面Spring告之hibernate的session在只讀事務(wù)模式下不用嘗試檢測和同步持久對象的狀態(tài)的更新。 總結(jié): 如果在使用事務(wù)的情況下,所有操作都是讀操作,那建議把事務(wù)設(shè)置成只讀事務(wù),或者事務(wù)的傳播途徑最好能設(shè)置為 supports (運行在當(dāng)前的事務(wù)范圍內(nèi),如果當(dāng)前沒有啟動事務(wù),那么就不在事務(wù)范圍內(nèi)運行)或者 not supports (不在事務(wù)范圍內(nèi)執(zhí)行,如果當(dāng)前啟動了事務(wù),那么掛起當(dāng)前事務(wù)),這樣不在事務(wù)下,就不會調(diào)用transactionContext.managedFlush(); 方法。 所有只讀事務(wù)與讀寫事務(wù)的比較大的運行性能區(qū)別就是只讀事務(wù)避免了Hibernate的檢測和同步持久對象的狀態(tài)的更新,提升了運行性能。 |
|