2010-08-16 13 views
11

मैं विशिष्ट सेवा घटनाओं के दौरान व्यापक प्रणाली को सूचित करने के लिए अपनी सेवा परत के भीतर स्प्रिंग एप्लिकेशन ईवेंट का उपयोग कर रहा हूं। मेरे पास यह मुद्दा है कि घटनाओं को एक लेनदेन संबंधी संदर्भ में निकाल दिया जाता है (मैं वसंत के @Transactional एनोटेशन का उपयोग कर रहा हूं)। खतरा यह है कि मैं एक घटना को आग लगाता हूं और फिर लेनदेन प्रतिबद्धता में विफल रहता है (उदाहरण के लिए, हाइबरनेट का उपयोग करते समय हो सकता है)। इस परिदृश्य में, ईवेंट श्रोताओं को कुछ राज्य माना जाएगा जो तब निष्पादित किए जाने के बाद वापस लुढ़काए जाएंगे। यहां का खतरा यह है कि, उदाहरण के लिए, मैंने वेबसाइट पर उपयोगकर्ता के पंजीकरण की पुष्टि करने के लिए एक ईमेल भेजा है, वास्तव में, वास्तव में, उनके उपयोगकर्ता खाते को वास्तव में नहीं बनाया गया था।स्प्रिंग ट्रांजैक्शन एनोटेशन - सफलता पर निष्पादन

क्या कोई तरीका है, एनोटेशन के उपयोग को संरक्षित करना, लेनदेन के बाद किसी घटना को ध्वस्त करने के लिए कहीं ध्वजांकित करना है? जावा स्विंग में जीयूआई प्रोग्रामिंग करते समय यह SwingUtilities.invokeLater(Runnable runnable) का उपयोग करने के समान कुछ लगता है। मैं कहना चाहता हूं कि वर्तमान लेनदेन सफलतापूर्वक काम करने के बाद कोड के इस बिट को बाद में निष्पादित करें।

कोई विचार?

धन्यवाद,

एंड्रयू

+0

यह सब वसंत में मूल रूप से संभाला अब एनोटेशन के माध्यम से है। https://spring.io/blog/2015/02/11/better-plplication-events-in-spring-framework-4-2https://spring.io/blog/2015/02/11/better देखें -प्पन-इवेंट-इन-स्प्रिंग-फ्रेमवर्क -4-2 विशेष रूप से नए @ ट्रांसेक्शनलएवेंट लिस्टनर एनोटेशन के बारे में अनुभाग। – PaulNUK

उत्तर

2

पुष्टिकरण ईमेल के साथ अपनी समस्या को हल करने के लिए उचित तरीके से शायद एक JMS संसाधन उन्हें में भाग लेने के साथ एक वितरित लेन-देन का प्रयोग है।

हालांकि, एक त्वरित और गंदे समाधान के रूप में, आप एक PlatformTransactionManager जिसके बाद Runnable कुछ ThreadLocal भंडारण में पंजीकृत रों निष्पादित करेंगे सफल प्रतिबद्ध के चारों ओर एक आवरण बनाने के लिए कोशिश कर सकते हैं (और रोलबैक के बाद ThreadLocal से हटाने)। असल में, AbstractPlatformTransactionManager में TransactionSynchronization एस के साथ बिल्कुल इस प्रकार का तर्क है, लेकिन इसे इसके कार्यान्वयन विवरण में बहुत गहरा दफनाया गया है।

+0

मैं अभी के लिए त्वरित और गंदे समाधान के साथ चला गया है। मैंने एक थ्रेडलोकल आधारित तंत्र बनाया है जो ट्रांज़ेक्शनस्टैटस ऑब्जेक्ट के साथ रननेबल ऑब्जेक्ट्स की कतार को जोड़ता है। TransactionStatus के प्रतिबद्ध() या रोलबैक() पर या तो रननेबल ऑब्जेक्ट निष्पादित करें या उन्हें छोड़ दें। यह काफी अच्छी तरह से काम करता है। – DrewEaster

+0

क्या आप एक कोड स्निपेट प्रदान कर सकते हैं? – Oliv

+0

मैं नहीं कहूंगा कि वितरित लेनदेन सही _proper_ समाधान हैं। वितरित लेनदेन पूरे लेनदेन में विफल होगा अगर केवल मेल भेजना विफल हो गया है। लेकिन यहां वांछित व्यवहार यह है कि मेल डीबी-लेनदेन पर निर्भर करता है और डीबी-लेनदेन मेल पर निर्भर नहीं करता है। – yair

4

आप PlatformTransactionManager को हैक करने की आवश्यकता के बिना TransactionSynchronizationManager का उपयोग कर सकते हैं।

नोट: लेनदेनअवेयर एक मार्कर इंटरफेस है जो दर्शाता है कि एक लेनदेन लेनदेन सफलतापूर्वक किए जाने के बाद एक कार्यक्रम प्राप्त करना चाहता है।

public class TransactionAwareApplicationEventMulticaster extends SimpleApplicationEventMulticaster { 

    @Override 
    public void multicastEvent(ApplicationEvent event) { 
     for (ApplicationListener listener : getApplicationListeners(event)) { 
      if ((listener instanceof TransactionAware) && TransactionSynchronizationManager.isSynchronizationActive()) { 
       TransactionSynchronizationManager.registerSynchronization(
        new EventTransactionSynchronization(listener, event)); 
      } 
      else { 
       notifyEvent(listener, event); 
      } 
     } 
    } 

    void notifyEvent(final ApplicationListener listener, final ApplicationEvent event) { 
      Executor executor = getTaskExecutor(); 
      if (executor != null) { 
       executor.execute(new Runnable() { 
        public void run() { 
         listener.onApplicationEvent(event); 
        } 
       }); 
      } 
      else { 
       listener.onApplicationEvent(event); 
      } 
    } 

    class EventTransactionSynchronization extends TransactionSynchronizationAdapter { 
     private final ApplicationListener listener; 
     private final ApplicationEvent event; 

     EventTransactionSynchronization(ApplicationListener listener, ApplicationEvent event) { 
      this.listener = listener; 
      this.event = event; 
     } 

     @Override 
     public void afterCompletion(int status) { 
      if ((phase == TransactionPhase.AFTER_SUCCESS) 
        && (status == TransactionSynchronization.STATUS_COMMITTED)) { 
       notifyEvent(listener, event); 
      } 
     } 
    } 
} 
10

यह मेरे लिए काम करता है:

TransactionSynchronizationManager.registerSynchronization(
    new TransactionSynchronizationAdapter() { 
     @Override 
     public void afterCommit() { 
      // things to do when commited 
     } 
     // other methods to override are available too 
    }); 
+0

अच्छा! प्रश्न आईएमओ के संबंध में सबसे अच्छा जवाब। यह SwingUtilities.invokeLater के समान है। –

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