2011-03-08 14 views
15

पर नेस्टेड लेनदेन ने नेस्टेड स्प्रिंग लेनदेन का उपयोग करते समय मुझे कुछ अजीब व्यवहार मिला: जब, उसी कक्षा में, @Transactional के रूप में एनोटेटेड विधि को @Transactional के रूप में भी एनोटेट किया गया दूसरा एनोटेशन का उपयोग नहीं किया जाता है।वसंत

के निम्नलिखित वर्ग पर ध्यान दें:

public class Main { 
    public static void main(String[] args) { 
     ApplicationContext context = new AnnotationConfigApplicationContext(Config.class); 
     final Main main = context.getBean(Main.class); 
     // First Op 
     System.out.println("Single insert: " + main.singleInsert()); 
     // Second Op 
     main.batchInsert(); 
     // Third Op 
     main.noTransBatchInsert(); 
    } 

    @PersistenceContext 
    private EntityManager pm; 

    @Transactional(propagation=Propagation.REQUIRED) 
    public void batchInsert() { 
     System.out.println("batchInsert"); 
     System.out.println("First insert: " + singleInsert()); 
     System.out.println("Second insert: " + singleInsert()); 
    } 

    public void noTransBatchInsert() { 
     System.out.println("noTransBatchInsert"); 
     System.out.println("First insert: " + singleInsert()); 
     System.out.println("Second insert: " + singleInsert()); 
    } 

    @Transactional(propagation=Propagation.REQUIRES_NEW) 
    public int singleInsert() { 
     System.out.println("singleInsert"); 
     Pojo p = new Pojo(); 
     pm.persist(p); 
     return p.getId(); 
    } 
} 

इकाई यदि निम्न वर्ग:

@Entity 
public class Pojo { 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private int id; 

    @Override 
    public String toString() { 
     return "Pojo: " + id; 
    } 

    public int getId() { 
     return id; 
    } 
} 

और स्ट्रिंग भागों applicationContext.xml:

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" 
    xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" 
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task" 
    xsi:schemaLocation=" 
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd 
    http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd 
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 
    http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"> 

    <tx:annotation-driven /> 

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> 
     <property name="persistenceUnitName" value="MyPersistenceUnit" /> 
    </bean> 

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

और विन्यास वर्ग (मैं इसे applicationContext.xml में विलय कर सकता था)।

@Configuration 
@ImportResource("/META-INF/applicationContext.xml") 
public class Config { 

    @Bean 
    public Main main() { 
     return new Main(); 
    } 
} 

पूर्णता के लिए persistence.xml फ़ाइल:

<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0"> 

    <persistence-unit name="MyPersistenceUnit" transaction-type="RESOURCE_LOCAL"> 
     <provider>org.hibernate.ejb.HibernatePersistence</provider> 

     <properties> 
      <property name="hibernate.hbm2ddl.auto" value="create" /> 
      <property name="hibernate.show_sql" value="true" /> 
      <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" /> 
      <property name="hibernate.connection.driver_class" value="org.h2.Driver" /> 
      <property name="hibernate.connection.url" value="jdbc:h2:mem:TestDSJPA2;DB_CLOSE_DELAY=-1;LOCK_MODE=0" /> 
      <!--<property name="hibernate.connection.url" value="jdbc:h2:mem:TestDSJPA2;DB_CLOSE_DELAY=-1;LOCK_MODE=0" />--> 
      <property name="hibernate.connection.username" value="sa" /> 
      <property name="hibernate.connection.password" value="" /> 
      <property name="hibernate.connection.autocommit" value="false"/> 

      <property name="hibernate.c3p0.min_size" value="5" /> 
      <property name="hibernate.c3p0.max_size" value="20" /> 
      <property name="hibernate.c3p0.timeout" value="300" /> 
      <property name="hibernate.c3p0.max_statements" value="50" /> 
      <property name="hibernate.c3p0.idle_test_period" value="3000" /> 
     </properties> 

    </persistence-unit> 
</persistence> 

तो मुख्य वर्ग में, पहला ऑपरेशन के रूप में की उम्मीद है कि एक नए सौदे में है किया जाता है। (कुछ डीबग संदेशों सहित) उत्पादन होता है:

DEBUG o.h.transaction.JDBCTransaction - begin 
singleInsert 
DEBUG o.h.transaction.JDBCTransaction - commit 
Single insert: 1 

दूसरे ऑपरेशन के बाद उत्पादन देता है:

batchInsert 
singleInsert 
DEBUG o.h.transaction.JDBCTransaction - begin 
First insert: 2 
singleInsert 
Second insert: 3 
DEBUG 

यह नहीं है कि मैं क्या उम्मीद के बाद से @Transactional(propagation=Propagation.REQUIRES_NEW) साथ singleInsert व्याख्या में मैं एक नया लेनदेन उम्मीद करेंगे प्रत्येक कॉल के लिए बनाया जाना चाहिए जो कि नहीं हो रहा है क्योंकि एक ही शीर्ष स्तर लेनदेन दोनों प्रविष्टियों के लिए उपयोग किया जाता है।

तीसरे आपरेशन के साथ-साथ कोई लेन-देन बिल्कुल बनाई गई है विफल रहता है:

noTransBatchInsert 
singleInsert 
DEBUG o.h.e.def.AbstractSaveEventListener - delaying identity-insert due to no transaction in progress 
First insert: 0 
singleInsert 
DEBUG o.h.e.def.AbstractSaveEventListener - delaying identity-insert due to no transaction in progress 
Second insert: 0 

@Configuration सेम स्प्रिंग सुनिश्चित है कि एक ही कक्षा proxified कर रहे हैं जो स्पष्ट रूप से है यहाँ नहीं हो रहा पर विधि करने के लिए कॉल में। क्या इस व्यवहार को बदलने का कोई तरीका है?

उत्तर

8

एओपी के लिए proxy मोड का उपयोग करते समय यह व्यवहार स्प्रिंग का दस्तावेजी व्यवहार है। इसे aspectj मोड पर स्विच करके बदला जा सकता है जो या तो संकलन या रनटाइम पर कोड उपकरण निष्पादित करता है।

6

यह विशेष रूप से @ ट्रांसेक्शनल के साथ कोई समस्या नहीं है। यह आपके <tx:annotation-driven/> की कॉन्फ़िगरेशन के कारण है।

वसंत दो अलग-अलग एओपी तंत्र का उपयोग करता है: जेडीके गतिशील प्रॉक्सी या CGLIB। जेडीके गतिशील प्रॉक्सी डिफ़ॉल्ट है और यह रन-समय पर इंटरफेस के उपयोग के माध्यम से काम करता है। CGLIB पर सबक्लास उत्पन्न करके-समय पर सबक्लास उत्पन्न करके काम करता है। यदि आप <tx:annotation-driven proxy-target-class="true"/> निर्दिष्ट करते हैं, तो वसंत CGLIB का उपयोग करेगा, और आपका दूसरा @ ट्रांसेक्शनल आग लगेगा।

आप विषय here विषय के बारे में अधिक पढ़ सकते हैं।