状況-ストーリータイム:
私はプログラムを「継承」しました。これは、データベースにアクセスするためのかなり単純なWebサービスです。このプログラムにはどこかに欠陥がありました。更新が許可されていないテーブルを更新しようとしました。プログラムには、データベースキュー(Oracle)を更新して、誰が何にアクセスしたかに関する情報を保存する権利しかありません。これは望ましくない動作でしたが、今では修正しました。注:これは、この質問自体には関係ありません。この質問に私を導いた原因にすぎません。
プログラムは、Spring + Hibernateを使用して、データとトランザクションを管理およびアクセスします。
プログラムの需要が高く、エラーが許容できないと見なされたため、ソフトウェアの中で実際に操作してはならないデータを操作する部分が見つかるまで、各トランザクションでロールバックを強制するだけで、修正プログラムを追加するという簡単なアイデアがありました。
ソフトウェアは2つの@Transactional
注釈を使用します。1つはプロセス全体で、もう1つはログデータの書き込み部分です。この2つ目は、Requires_New
伝播設定で使用されました。私が理解している限り、この2番目のトランザクションは常に新しいトランザクションを作成し、そのスパン(この場合は1つのメソッド)が終了したときにそれをフラッシュします。
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
次に、ネストされたトランザクションがすでに終了した後に直接ロールバックステートメントを追加して、外部トランザクションをロールバックしました(したがって、操作を元に戻します)。しかし、それはそのようには機能しませんでした。両方のトランザクションがロールバックされました。誰かが私にこれが起こった理由へのポインタを教えてもらえますか?システムがどのように機能するかを私が知っていると私が思っていたものとは少し矛盾しています。currentTransactionStatus()
現在のセッションに関連付けられているすべてのトランザクションが含まれていますか?
関連するコードスニペット(わかりやすくするための短縮形)
@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 />