2015-02-12 7 views
6

Ich habe das folgende Szenario. Ich benutze JPA, Spring:Propagation.REQUIRES_NEW erstellt keine neue Transaktion im Frühjahr mit JPA

@Autowired 
SampleService service; 

@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) 
public void PerformLogic(LogicData data) throws SIASFaultMessage 
{ 
    SampleObject so = createSampleObject(); 

    try{ 
     .//do some logic to persist things in data 
     . 
     . 
     persistData(data); 
     . 
     . 
     . 


     updateSampleObject(so);  
    } 
    catch(Exception){ 
     updateSampleObject(so);  
     throw new SIASFaultMessage(); 
    } 

} 

@Transactional(propagation = Propagation.REQUIRES_NEW) 
public createSampleObject() 
{ 
    SampleObject so = new SampleObject(); 

    . 
    .//initialize so 
    . 

    service.persist(so);   
    return so; 
} 

@Transactional(propagation = Propagation.REQUIRES_NEW) 
public updateSampleObject(SampleObject so) 
{    
    service.persist(so);   
    return so; 
} 

Wenn alles funktioniert, bleiben Daten in der Datenbank ohne Probleme persistent. Wenn jedoch eine Ausnahme ausgelöst wird, muss die Methode updateSampleObject (so) die Informationen in der Datenbank beibehalten. Das ist nicht was passiert. Wenn eine Ausnahme ausgelöst wird, wird auch die Methode updateSampleObject zurückgesetzt, was ich nicht brauche. Ich brauche, dass diese beiden Methoden (createSampleObject und updateSampleObject) die ganze Zeit beibehalten, egal ob eine Ausnahme ausgelöst wurde oder nicht. Wie kann ich das erreichen?

Außerdem, wenn ich die Methoden anotate createSampleObject und updateSampleObject mit:

@Transactional(propagation = Propagation.NEVER) 

die Idee ist, dass eine Ausnahme ausgelöst wird, und ich bekomme keine Ausnahme ausgelöst. Wo ist das Problem? Analizing die Protokolle sehe ich diese Zeile:

org.springframework.orm.jpa.JpaTransactionManager ==> Creating new transaction with name [com.test.PerformLogic]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT.... 

, die diese Transaktion Mittel erstellt, aber ich sehe keinen Hinweis auf die andere Transaktion.

Dies ist der Teil meiner Konfigurationsdatei für den Frühling in Bezug auf Transaktionen

<bean id="myDataSource" 
     class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
    <property name="driverClassName" value="${jdbc.driverClassName}"/> 
    <property name="url" value="${jdbc.url}"/> 
    <property name="username" value="${jdbc.username}"/> 
    <property name="password" value="${jdbc.password}"/> 
</bean> 
<bean id="entityManagerFactory" 
     class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="dataSource" ref="myDataSource"/> 
    <property name="packagesToScan" value="cu.jpa"/> 
    <property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"/> 
    <property name="jpaProperties"> 
     <props> 
      <prop key="hibernate.dialect">${hibernate.dialect}</prop> 
      <prop key="hibernate.show_sql">true</prop> 
      <prop key="hibernate.hbm2ddl.auto">${hdm2ddl.auto}</prop> 
     </props> 
    </property> 
    <property value="/META-INF/jpa-persistence.xml" name="persistenceXmlLocation"/> 
    <property name="persistenceUnitName" value="jpaPersistenceUnit"/> 
</bean> 

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
    <property name="entityManagerFactory" ref="entityManagerFactory"/> 
    <property name="nestedTransactionAllowed" value="true" /> 
</bean> 

<tx:annotation-driven transaction-manager="transactionManager"/> 

Antwort

22

Spring-Transaktionen sind proxybasiert. So funktioniert es, wenn Bean A eine Transaktion von Bean B verursacht. A hat tatsächlich einen Verweis auf einen Proxy, der an die Bean B delegiert. Dieser Proxy ist derjenige, der die Transaktion startet und festschreibt/rollt:

A ---> proxy ---> B 

In Ihrem Code ruft eine Transaktionsart von A eine andere Transaktionsart von A auf. So kann Spring den Aufruf nicht abfangen und eine neue Transaktion starten. Es ist ein normaler Methodenaufruf ohne Proxy.

Wenn Sie also eine neue Transaktion starten möchten, sollte die Methode createSampleObject() in einer anderen Bean sein, die in Ihre aktuelle Bean injiziert wird.

Dies wird mit weiteren Details in the documentation erklärt.

+1

Danke, das war es. Ich werde die Frühjahrsdokumentation genauer unter die Lupe nehmen. Wissen Sie, ob es einen Weg gibt, dass die Transaktionen nicht auf Proxy-basiert, sondern auf der Methode funktionieren? –

+1

@AlfredoA. Es ist möglich, wenn Sie das Webzeitverhalten von AspectJ verwenden, um den Code byteweise zu laden, wodurch die Notwendigkeit von Proxies, wie oben erwähnt, entfällt. Auf diese Weise kann die Transaktionsmethode foo() der Klasse A die Transaktionsmethode bar(), ebenfalls der Klasse A, aufrufen, und bar() wird innerhalb ihrer eigenen Transaktion ausgeführt. Weitere Informationen hierzu finden Sie in der oben verlinkten Spring Framework-Dokumentation. – Aquarelle

+0

Danke eine Tonne.Ich habe viel gesucht, wenn die Transaktion ausgeführt wird, da ich zwei verschiedene Transaktionen habe, von denen eine vom Ergebnis anderer abhängt. Es hat mit "Required" & "Requires_New" funktioniert aber nur wenn ich dann in andere Beans lege. –

4

Meine Vermutung ist, dass da beide Methoden in der gleichen Bohne sind, AOP des Spring keine Chance hat, die create/updateSampleObject abfangen Methodenaufrufe. Versuchen Sie, die Methoden in eine separate Bean zu verschieben.

+0

Vielen Dank, das war es. Ich würde es als korrekt markieren, aber ich lese erst das andere zuerst. –

Verwandte Themen