2012-10-28 49 views
8

मेरे पास एक विश्वसनीय API है जो @EntityListners के साथ एनोटेटेड इकाई इकाई का उपयोग करता है। और EntityListner.java में, मेरे पास @PostPersist के साथ एनोटेटेड एक विधि है। इसलिए, जब वह घटना आग लगती है, तो मैं उस इकाई के बारे में सारी जानकारी निकालना चाहता हूं जो अभी डेटाबेस के लिए जारी है। लेकिन जब मैं ऐसा करने की कोशिश करता हूं, तो ग्लासफ़िश एक अपवाद उत्पन्न कर रहा है और EntityListner क्लास में विधि अपेक्षित रूप से निष्पादित नहीं हो रही है। अगर मैं successMessage बाहर टिप्पणी की संदेश बजाय भेज की custData यहाँ कोडइकाई डेटा प्राप्त करने के लिए जेपीए जीवन-चक्र घटनाओं का उपयोग कैसे करें

public class EntityListner { 
private final static String QUEUE_NAME = "customer"; 
@PostUpdate 
@PostPersist 
public void notifyOther(Customer entity){ 
    CustomerFacadeREST custFacade = new CustomerFacadeREST(); 
    Integer customerId = entity.getCustomerId(); 
    String custData = custFacade.find(customerId).toString(); 
    String successMessage = "Entity added to server"; 
    try{ 
     ConnectionFactory factory = new ConnectionFactory(); 
     factory.setHost("localhost"); 
     Connection connection = factory.newConnection(); 
     Channel channel = connection.createChannel(); 

     channel.queueDeclare(QUEUE_NAME, false, false, false, null); 
     // channel.basicPublish("", QUEUE_NAME, null, successMessage .getBytes()); 
     channel.basicPublish("", QUEUE_NAME, null, custData.getBytes()); 
     channel.close(); 
     connection.close(); 


    } 
    catch(IOException ex){ 

    } 
    finally{ 

    } 
    }  
} 

है, सब कुछ ठीक काम करता है।

http://www.objectdb.com/java/jpa/persistence/event इकाई जीवन चक्र विधियों के बारे में निम्नलिखित कहते हैं, और मैं सोच रहा हूं कि यह स्थिति यहां है या नहीं।

मूल डेटाबेस कार्रवाई उस संस्था जीवन चक्र घटना (जो अभी भी चल रहा है) कॉलबैक तरीकों EntityManager या क्वेरी तरीकों नहीं बुलाना चाहिए और किसी भी अन्य संस्था वस्तुओं

संपर्क नहीं करना चाहिए आग के साथ संघर्ष से बचने के लिए कोई विचार?

+0

आपको क्या अपवाद मिल रहा है? –

+0

अपवाद और स्टैक ट्रेस शामिल करें। – James

उत्तर

8

जैसा कि पैराग्राफ कहता है, मानक अंदरूनी इकाई श्रोताओं से कॉलिंग इकाई प्रबंधक विधियों का समर्थन नहीं करता है। I दृढ़ता से दृढ़ इकाई से custData बनाने की अनुशंसा करते हैं, क्योंकि हेइको रूपप उनके उत्तर में कहते हैं। यदि यह व्यवहार्य नहीं है, तो विचार करें:

  • असीमित रूप से अधिसूचित। (यदि Heilo रप जवाब संभव नहीं है मेरी सिफारिश) कुछ बाद प्रतिबद्ध ट्रिगर दर्ज की
 
public class EntityListener { 
    private final static String QUEUE_NAME = "customer"; 

    private ScheduledExecutorService getExecutorService() { 
     // get asynchronous executor service from somewhere 
     // you will most likely need a ScheduledExecutorService 
     // instance, in order to schedule notification with 
     // some delay. Alternatively, you could try Thread.sleep(...) 
     // before notifying, but that is ugly. 
    } 

    private void doNotifyOtherInNewTransaction(Customer entity) { 
     // For all this to work correctly, 
     // you should execute your notification 
     // inside a new transaction. You might 
     // find it easier to do this declaratively 
     // by invoking some method demarcated 
     // with REQUIRES_NEW 
     try { 
      // (begin transaction) 
      doNotifyOther(entity); 
      // (commit transaction) 
     } catch (Exception ex) { 
      // (rollback transaction) 
     } 
    } 

    @PostUpdate 
    @PostPersist 
    public void notifyOther(final Customer entity) { 
     ScheduledExecutorService executor = getExecutorService(); 
     // This is the "raw" version 
     // Most probably you will need to call 
     // executor.schedule and specify a delay, 
     // in order to give the old transaction some time 
     // to flush and commit 
     executor.execute(new Runnable() { 
      @Override 
      public void run() { 
       doNotifyOtherInNewTransaction(entity); 
      } 
     }); 
    } 

    // This is exactly as your original code 
    public void doNotifyOther(Customer entity) { 
     CustomerFacadeREST custFacade = new CustomerFacadeREST(); 
     Integer customerId = entity.getCustomerId(); 
     String custData = custFacade.find(customerId).toString(); 
     String successMessage = "Entity added to server"; 
     try { 
      ConnectionFactory factory = new ConnectionFactory(); 
      factory.setHost("localhost"); 
      Connection connection = factory.newConnection(); 
      Channel channel = connection.createChannel(); 
      channel.queueDeclare(QUEUE_NAME, false, false, false, null); 
      channel.basicPublish("", QUEUE_NAME, null, custData.getBytes()); 
      channel.close(); 
      connection.close(); 
     } 
     catch(IOException ex){ 
     } 
     finally { 
     } 
    }  
} 
  • : मैं वास्तव में इस की सिफारिश करते हैं नहीं के रूप में यह शायद समय पर निर्भर करता है ठीक से काम करने के लिए। यह समय पर निर्भर नहीं है क्योंकि डेटाबेस में फ़्लश होने के बाद इसे निष्पादित करने की गारंटी है। इसके अलावा, इसमें अतिरिक्त लाभ भी है जो आप सूचित नहीं करते हैं कि क्या आप अपने लेन-देन को वापस लेते हैं। ऐसा करने का तरीका लेनदेन प्रबंधन के लिए आप जो उपयोग कर रहे हैं उस पर निर्भर करता है, लेकिन मूल रूप से आप कुछ विशेष उदाहरण का उदाहरण बनाते हैं और फिर इसे कुछ रजिस्ट्री में पंजीकृत करते हैं। उदाहरण के लिए, JTA साथ यह होगा:
 
public class EntityListener { 
    private final static String QUEUE_NAME = "customer"; 

    private Transaction getTransaction() { 
     // get current JTA transaction reference from somewhere 
    } 

    private void doNotifyOtherInNewTransaction(Customer entity) { 
     // For all this to work correctly, 
     // you should execute your notification 
     // inside a new transaction. You might 
     // find it easier to do this declaratively 
     // by invoking some method demarcated 
     // with REQUIRES_NEW 
     try { 
      // (begin transaction) 
      doNotifyOther(entity); 
      // (commit transaction) 
     } catch (Exception ex) { 
      // (rollback transaction) 
     } 
    } 

    @PostUpdate 
    @PostPersist 
    public void notifyOther(final Customer entity) { 
     Transaction transaction = getTransaction(); 
     transaction.registerSynchronization(new Synchronization() { 
      @Override 
      public void beforeCompletion() { } 

      @Override 
      public void afterCompletion(int status) { 
       if (status == Status.STATUS_COMMITTED) { 
        doNotifyOtherInNewTransaction(entity); 
       } 
      } 
     });    
    } 

    // This is exactly as your original code 
    public void doNotifyOther(Customer entity) { 
     CustomerFacadeREST custFacade = new CustomerFacadeREST(); 
     Integer customerId = entity.getCustomerId(); 
     String custData = custFacade.find(customerId).toString(); 
     String successMessage = "Entity added to server"; 
     try { 
      ConnectionFactory factory = new ConnectionFactory(); 
      factory.setHost("localhost"); 
      Connection connection = factory.newConnection(); 
      Channel channel = connection.createChannel(); 
      channel.queueDeclare(QUEUE_NAME, false, false, false, null); 
      channel.basicPublish("", QUEUE_NAME, null, custData.getBytes()); 
      channel.close(); 
      connection.close(); 
     } 
     catch(IOException ex){ 
     } 
     finally { 
     } 
    }  
} 

आप वसंत लेनदेन का उपयोग कर रहे हैं, तो कोड सिर्फ कुछ वर्ग के नाम में परिवर्तन के साथ, बहुत समान हो जाएगा।

कुछ संकेत दिए गए:

3

मुझे लगता है कि आप एक एनपीई दिखाई जा रही है के रूप में आप पैरा आप का हवाला देते हुए थे उल्लंघन करने जा सकता है:

String custData = custFacade.find(customerId).toString(); 

find परोक्ष वस्तु के लिए क्वेरी करने के लिए (आप का वर्णन के रूप में) लगता है, जो नहीं हो सकता है पूरी तरह से डेटाबेस से समन्वयित और इस प्रकार अभी तक सुलभ नहीं है।

+0

धन्यवाद @ हेको; हाँ, मुझे एनपीई मिल रहा है। मैंने डेटाबेस को सिंक करने के लिए पर्याप्त समय देने के लिए थ्रेड.sleep (2000) जोड़ा लेकिन इसका कोई फायदा नहीं हुआ। तो, क्या कोई काम है? – Abraham

+2

क्या आप उस ग्राहक ऑब्जेक्ट का उपयोग नहीं कर सकते जो पारित किया गया था? –

+0

मैं उस तर्क के जेसन का प्रतिनिधित्व वापस पढ़ना चाहता हूं कि जर्सी इसे बनाने के लिए उपयोग करता था। अगर मैं उस तर्क का उपयोग करता हूं जिसे मैं भेजता हूं, तो मुझे केवल आईडी मिलती है। – Abraham

1

उसके जवाब में, gpeche कहा कि यह वसंत में अपने विकल्प # 2 अनुवाद करने के लिए काफी सीधा है। दूसरों कि कर की परेशानी सहेजने के लिए:

package myapp.entity.listener; 

import javax.persistence.PostPersist; 
import javax.persistence.PostUpdate; 
import org.springframework.transaction.support.TransactionSynchronizationAdapter; 
import org.springframework.transaction.support.TransactionSynchronizationManager; 
import myapp.util.ApplicationContextProvider; 
import myapp.entity.NetScalerServer; 
import myapp.service.LoadBalancerService; 

public class NetScalerServerListener { 

    @PostPersist 
    @PostUpdate 
    public void postSave(final NetScalerServer server) { 
     TransactionSynchronizationManager.registerSynchronization(
      new TransactionSynchronizationAdapter() { 

       @Override 
       public void afterCommit() { postSaveInNewTransaction(server); } 
      }); 
    } 

    private void postSaveInNewTransaction(NetScalerServer server) { 
     ApplicationContext appContext = 
      ApplicationContextProvider.getApplicationContext(); 
     LoadBalancer lbService = appContext.getBean(LoadBalancerService.class); 
     lbService.updateEndpoints(server); 
    } 
} 

सेवा विधि (यहाँ, updateEndpoints()) किसी भी मुद्दे के बिना (प्रश्नों और अद्यतन संस्थाओं जारी करने के लिए, मेरे मामले में) जेपीए EntityManager उपयोग कर सकते हैं। @Transaction(propagation = Propagation.REQUIRES_NEW) के साथ updateEndpoints() विधि को एनोटेट करना सुनिश्चित करें ताकि दृढ़ता संचालन करने के लिए एक नया लेनदेन हो।

सीधे प्रश्न से संबंधित नहीं है, लेकिन ApplicationContextProvider एक ऐप संदर्भ वापस करने के लिए सिर्फ एक कस्टम क्लास है क्योंकि जेपीए 2.0 इकाई श्रोताओं प्रबंधित घटक नहीं हैं, और मैं यहां का उपयोग करने के लिए बहुत आलसी हूं। यहां यह पूर्णता के लिए है:

package myapp.util; 

import org.springframework.beans.BeansException; 
import org.springframework.context.ApplicationContext; 
import org.springframework.context.ApplicationContextAware; 

public class ApplicationContextProvider implements ApplicationContextAware { 
    private static ApplicationContext applicationContext; 

    public static ApplicationContext getApplicationContext() { 
     return applicationContext; 
    } 

    @Override 
    public void setApplicationContext(ApplicationContext appContext) 
      throws BeansException { 

     applicationContext = appContext; 
    } 
}