情況 - 故事時間:
我「繼承了」一個程序,一個用於訪問數據庫的相當簡單的web服務。這個程序有一個缺點:它試圖更新一個沒有更新授權的表。該程序只有更新數據庫隊列(Oracle)的權利,以保存訪問內容的信息。這是不受歡迎的行爲,現在我已經修復了它。注意:這與這個問題本身無關,只是導致我這個問題的原因。強制回滾事務導致嵌套事務也回滾?
該程序使用Spring + Hibernate來管理和訪問數據和事務。因爲程序需求量很大,錯誤被認爲是不可容忍的,所以我有一個快速的想法來添加一個修補程序,只是爲了強制每個事務回滾,直到我發現軟件的一部分實際上處理數據時它應該不操縱。
該軟件使用2 @Transactional
註釋。一個是整個過程,另一個是寫日誌數據。第二個與Requires_New
傳播設置一起使用。據我瞭解,第二個總是會創建一個新的Transaction,並在其跨度(在這種情況下:一個方法)結束時刷新它。
然後我在嵌套事務結束後添加了一個直接回滾語句TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
來回滾外部事務(爲了撤銷操作)。但它沒有那樣工作。這兩個事務都回滾了。任何人都可以給我指出爲什麼發生這種情況?它有點相互衝突,我認爲我知道系統是如何工作的。 currentTransactionStatus()
是否包含與當前會話關聯的所有交易?
相關代碼段(shortend爲清楚起見)
@Override
@Transactional
@PreAuthorize(Rollen.INFOVN)
public InfoVNAntwort infoVNAnfrage(final InfoVNAnfrage infoVNAnfrage) {
// extract data from request
final InfoVNDatenhalter datenhalter = (InfoVNDatenhalter) this.getController().erzeugeNeuenDatenhalter(ProzessNamen.INFOVN);
datenhalter.setAnfrageFin(StringUtils.trimToNull(infoVNAnfrage.getFIN()));
datenhalter.setAnfrageZB2(StringUtils.trimToNull(infoVNAnfrage.getZB2()));
final String username = this.getCurrentUserName();
datenhalter.setBenutzerkennung(username);
datenhalter.setErgaenzungstext(infoVNAnfrage.getErgaenzungstext());
datenhalter.setAnfragegrund(infoVNAnfrage.getAnfrageanlass());
// actual fetch of database data
final DialogAntwort da = (DialogAntwort) this.getController().verarbeite(datenhalter);
// convert to ws response
final InfoVNAntwort vnAntwort = this.getMapper().map(da, InfoVNAntwort.class);
// log who did what
this.erstelleBewirt(vnAntwort, infoVNAnfrage, new DateTime(), username);
// roll back outer transaction
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return vnAntwort;
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
private void erstelleBewirt(final InfoVNAntwort vnAntwort, final InfoVNAnfrage infoVNAnfrage, final DateTime zeitpunktAuskunft, final String username) {
final InfoVNBewirt eintrag = new InfoVNBewirt();
eintrag.setZeitpunktErteilungAuskunft(zeitpunktAuskunft);
eintrag.setSteuerelement(STEUERELEMENT_INFOVN);
eintrag.setAnfrageAnlass(infoVNAnfrage.getAnfrageanlass());
this.completeEintrag(username, eintrag);
this.logdatenPersister.persistiereLogdaten(eintrag);
}
於數據庫的連接:
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="packagesToScan">
<list>
<value>de.mm.vwn</value>
<value>de.mm.cfo.allgemein.kenauthent</value>
<value>de.mm.cfo.infovn.logdaten</value>
</list>
</property>
<property name="hibernateProperties" ref="hibernateProperties"></property>
</bean>
<bean id="hibernateProperties"
class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="properties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.hbm2ddl.auto">none</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.region.factory_class">net.sf.ehcache.hibernate.EhCacheRegionFactory</prop>
<prop key="hibernate.jdbc.use_scrollable_resultset">true</prop>
<prop key="hibernate.jdbc.batch_size">25</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="dataSource" ref="dataSource" />
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<tx:annotation-driven />
不,這是不正常的,除非你不經歷事務代理調用具有REQUIRES_NEW的方法。告訴我們你的代碼。 – 2012-07-06 10:17:14