2010-05-26 15 views
7

के लिए वसंत लेनदेन समर्थन के अजीब befaviour मुझे अपेक्षाकृत सरल उपयोग मामले पर वास्तव में अजीब व्यवहार पता चला, शायद मैं वसंत @ ट्रान्सैक्शनल प्रकृति के गहरे ज्ञान के बारे में नहीं समझ सकता, लेकिन यह है काफी दिलचस्प।जेपीए + हाइबरनेट + @ ट्रांज़ेक्शनल एनोटेशन

@Transactional 
public User save(User user) { 
    getJpaTemplate().persist(user); 
    return user; 
} 

तो जब तक मैं एक ही वर्ग के लिए नई विधि जोड़ने है ठीक काम कर रहा था: उपयोगकर्ता getSuperUser(), इस विधि चाहिए

मैं सरल उपयोगकर्ता दाव कि वसंत JpaDaoSupport वर्ग प्रदान करता है और विधि बचाने मानक शामिल है isAdmin == सत्य के साथ उपयोगकर्ता को वापस करें, और यदि डीबी में कोई सुपर उपयोगकर्ता नहीं है, तो विधि को एक बनाना चाहिए। यही कि यह कैसे की तरह देख रहा था:

public User createSuperUser() { 
    User admin = null; 

    try { 
     admin = (User) getJpaTemplate().execute(new JpaCallback() { 
      public Object doInJpa(EntityManager em) throws PersistenceException { 
       return em.createQuery("select u from UserImpl u where u.admin = true").getSingleResult(); 
      } 
     }); 
    } catch (EmptyResultDataAccessException ex) { 
     User admin = new User('login', 'password'); 
     admin.setAdmin(true); 
     save(admin); // THIS IS THE POINT WHERE STRANGE THING COMING OUT 
    } 

    return admin; 
} 

जैसा कि आप देख कोड अजीब आगे है और जब पता चला कि कोई लेनदेन बनाया गया था और सेव (व्यवस्थापक) विधि के आह्वान पर प्रतिबद्ध है और कोई नया उपयोगकर्ता नहीं था मैं बहुत उलझन में था वास्तव में @Transactional एनोटेशन के बावजूद बनाया गया।

परिणामस्वरूप हमारे पास स्थिति है: जब saveDA() विधि UserDAO क्लास के बाहर से आती है - @ ट्रांस्सेन्शनल एनोटेशन गिनती और उपयोगकर्ता सफलतापूर्वक बनाया गया है, लेकिन अगर सहेज() उसी दाओ वर्ग की अन्य विधि के अंदर से आक्रमण करता है - @ ट्रान्ससेनल एनोटेशन अनदेखा किया।

यहां मैं कैसे परिवर्तन() विधि को बदलने के लिए इसे हमेशा लेनदेन बनाने के लिए मजबूर करता था।

public User save(User user) { 
    getJpaTemplate().execute(new JpaCallback() { 
     public Object doInJpa(EntityManager em) throws PersistenceException { 
      em.getTransaction().begin(); 
      em.persist(user); 
      em.getTransaction().commit(); 
      return null; 
     } 
    }); 
    return user; 
} 

जैसा कि आप देखते हैं कि मैं मैन्युअल रूप से शुरूआत करता हूं और प्रतिबद्ध करता हूं। कोई विचार?

उत्तर

5

मुझे लगता है कि एनोटेशन के साथ घोषणात्मक लेनदेन प्रॉक्सी के आधार पर लागू किया गया है।

यदि आप गतिशील प्रॉक्सी के माध्यम से अपने डीएओ तक पहुंचते हैं तो यह जांचता है कि कोई एनोटेशन है और लेनदेन के साथ इसे लपेटता है।

यदि आप कक्षा के अंदर से अपनी कक्षा को कॉल करते हैं तो इस कॉल को रोकने का कोई तरीका नहीं है।

समस्या से बचने के लिए आप createSuperuser विधि को एनोटेशन के साथ भी चिह्नित कर सकते हैं।

+1

इस तरह के गहरे स्पष्टीकरण के लिए धन्यवाद, वैसे, अगर मैं पहलू को सक्रिय करूंगा क्योंकि मुझे पता है कि पहलू गतिशील प्रॉक्सी का विकल्प है। createSuperuser को लेन-देन के रूप में चिह्नित करने के लिए यह समझ में नहीं आता है, जब तक कि मैं इसे अभी भी उसी वर्ग में getSuperUser के अंदर से आमंत्रित करता हूं, लेकिन हाँ - जब मैं getSuperUser लेनदेन को चिह्नित करता हूं - सब कुछ ठीक काम करता है – abovesun

7
  1. @Transactional केवल ऑब्जेक्ट के बाहर से कॉल के लिए खाते में लिया जाता है। अंदरूनी कॉल के लिए यह नहीं है। इसके आसपास काम करने के लिए बस अपने प्रविष्टि बिंदु पर @Transactional जोड़ें।
  2. अपने डीएओ के लिए @Transactional का उपयोग न करें - इसके बजाय सेवा कक्षाओं पर इसका उपयोग करें।
+0

धन्यवाद, इस विषय के बारे में वसंत डॉक्टर को फिर से पढ़ा जाएगा! – abovesun

+0

सेवा पद्धति को लेन-देन के रूप में चिह्नित करने के लिए हमेशा समझदारी नहीं होती है, मेरे पास मेरे ऐप में 2 प्लग करने योग्य निरंतर प्रदाता है, एक जेपीए + हाइबरनेट है, दूसरा मोंगोडीबी + कस्टम डीएओ है, और शायद तीसरा एक - कैसंद्रा समर्थन होगा। तो @Transactional केवल जेपीए सक्रिय होने पर ही समझ में आता है। – abovesun

+0

काफी लेनदेन संबंधी व्यवहार एक पार-दृढ़ता-तंत्र अवधारणा नहीं है। सच है, जेपीए लेनदेन की मांग करता है, जबकि अन्य तंत्र नहीं करते हैं, लेकिन लेनदेन अभी भी मौजूद हैं। और एक उचित लेनदेन प्रबंधक के साथ, सेवा स्तर पर एनोटेशन का उपयोग करना समझ में आता है। – Bozho

0

आपकी समस्या स्प्रिंग एओपी की सीमाओं से संबंधित है। Bozho answer एक अच्छा है और आपको अपनी सलाह का समर्थन करने के लिए अपने कोड को दोबारा विचार करना चाहिए।

लेकिन यदि आप चाहते हैं कि आपका लेनदेन किसी भी कोड को बदले बिना काम करे, तो यह संभव है!

स्प्रिंग एओपी स्प्रिंग पहलुओं प्रौद्योगिकियों में डिफ़ॉल्ट विकल्प है। लेकिन कुछ कॉन्फ़िगरेशन और AspectJ बुनाई जोड़ने के साथ, यह काम करेगा, क्योंकि AspectJ एक और अधिक शक्तिशाली तकनीक है जो उसी वर्ग में दो विधियों के बीच पॉइंटकूट सक्षम करती है।

+0

धन्यवाद एस्पेन, आपने मेरे उत्तर दिया आपके उत्तर के जवाब के लिए टिप्पणी करें – abovesun

संबंधित मुद्दे