2012-01-07 7 views
7

मैं डेटाबेस के लिए एक वस्तु (ReportBean) लागू करने के लिए चाहता था, लेकिन मैं त्रुटि संदेश मिला:कंटेनर प्रबंधित लेनदेन (सीएमटी) को कैसे कार्यान्वित करें?

javax.persistence.TransactionRequiredException: Transaction is required to perform this operation (either use a transaction or extended persistence context) 

यहाँ एक कोड का एक सा है:

इकाई

@Entity 
@Table(name="t_report") 
@Access(AccessType.FIELD) 
public class ReportBean implements Serializable { 

    // fields (@Column, etc.) 
    // setters/getters methods 
    // toString , hashCode, equals methods 
} 

कस्टम एनोटेशन एंटीटीमैनेजर इंजेक्शन (@Inject के साथ)

की अनुमति के लिए
import javax.inject.Qualifier; 
import static java.lang.annotation.ElementType.*; 
import java.lang.annotation.Target; 

@Qualifier 
@Target({TYPE, METHOD, FIELD, PARAMETER}) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface MyEm { 
} 

EntityManager प्रदाता

import javax.enterprise.inject.Produces; 
import javax.persistence.EntityManager; 
import javax.persistence.PersistenceContext; 
import javax.persistence.PersistenceContextType; 

public class EntityManagerProvider { 

    private final String PERSISTENCE_UNIT = "MyPersistenceUnit"; 

    @SuppressWarnings("unused") 
    @Produces 
    @MyEm 
    @PersistenceContext(unitName=PERSISTENCE_UNIT, type=PersistenceContextType.TRANSACTION) 
    private EntityManager em; 

} 

ValidateReportAction वर्ग - डेटाबेस के लिए रिपोर्ट लागू करने के लिए एक विधि है।
मैं सबसे महत्वपूर्ण आयात के साथ चिपकने की कोशिश कर रहा हूं।
यदि मैं कोई प्रश्न बनाने के लिए EntityManager का उपयोग करना चाहता हूं (या उदाहरण के रूप में NamedQuery) सबकुछ काम करता है।

import javax.inject.Inject; 
import javax.inject.Named; 
import javax.persistence.EntityManager; 
import javax.ejb.TransactionAttribute; 
import javax.ejb.TransactionAttributeType; 
import javax.ejb.TransactionManagement; 
import javax.ejb.TransactionManagementType; 
import javax.enterprise.context.SessionScoped; 


@Named("validateReportAction") 
@SessionScoped 
@TransactionManagement(TransactionManagementType.CONTAINER) 
public class ValidateReportAction extends ReportAction implements Serializable { 

    private static final long serialVersionUID = -2456544897212149335L; 

    @Inject @MyEm 
    private EntityManager em; 

    @TransactionAttribute(TransactionAttributeType.REQUIRED) 
    public synchronized String createReport() { 
     ReportBean report = new Report(); 
     // set report properties 
     // em.createNamedQuery("queryName").getResultList(); ---- works 
     em.persist(report) 
    } 
} 

Q: यहाँ createReport() विधि जब em.persist निष्पादित करता है, जहां त्रुटि दिखाई देते हैं। मैंने सोचा कि लेनदेन कंटेनर द्वारा प्रबंधित किया जाता है (CMT), लेकिन अब मुझे लगता है कि मैं गलत हूं। मैंने गलती कहाँ की है? सीएमटी को लागू करने का सही तरीका क्या है?

<?xml version="1.0" encoding="UTF-8"?> 
<persistence version="2.0" 
    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"> 

    <persistence-unit name="MyPersistenceUnit" transaction-type="JTA"> 

     <provider>org.hibernate.ejb.HibernatePersistence</provider> 
     <jta-data-source>java:jboss/TimeReportDS</jta-data-source> 
     <mapping-file>META-INF/orm.xml</mapping-file> 

     <class>....</class> 
     <class>....</class> 
     <class>....</class> 

     <properties> 

      <property name="jboss.entity.manager.factory.jndi.name" 
       value="java:/modelEntityManagerFactory" /> 

      <!-- PostgreSQL Configuration File --> 
      <property name="hibernate.connection.driver_class" value="org.postgresql.Driver" /> 
      <property name="hibernate.connection.password" value="password" /> 
      <property name="hibernate.connection.url" value="jdbc:postgresql://192.168.2.125:5432/t_report" /> 
      <property name="hibernate.connection.username" value="username" /> 

      <!-- Specifying DB Driver, providing hibernate cfg lookup 
       and providing transaction manager configuration --> 
      <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" /> 
      <property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory"/> 
      <property name="hibernate.transaction.manager_lookup_class" 
       value="org.hibernate.transaction.JBossTransactionManagerLookup" /> 
      <property name="hibernate.archive.autodetection" value="class" /> 

      <!-- Useful configuration during development - developer can see structured SQL queries --> 
      <property name="hibernate.show_sql" value="true" /> 
      <property name="hibernate.format_sql" value="false" /> 

     </properties> 
    </persistence-unit> 
</persistence> 

कृपया मुझे बताएं कि मेरे सवाल में कुछ स्पष्ट नहीं है करते हैं:

यहाँ भी मेरी persistence.xml विन्यास है।

उत्तर

18

मैंने गलती कहाँ की है?

आपको लगता है कि @TransactionManagement(TransactionManagementType.CONTAINER) सक्षम बनाता है कंटेनर में कामयाब रहे लेनदेन और कि @TransactionAttribute(TransactionAttributeType.REQUIRED) तो एक गैर EJB सेम के लिए, एक विधि पर लेन-देन के लिए सक्षम बनाता सोचने के लिए लग रहे हैं।

हालांकि यह जावा ईई में अभी तक संभव नहीं है (अभी तक) संभव है।

@TransactionManagement एनोटेशन केवल ईजेबी बीन को स्विच करने के लिए उपयोग किया जाता है जो कंटेनर से बीएमटी (बीन प्रबंधित लेनदेन) में पहले ही सीएमटी प्राप्त करता है। CONTAINER निरंतरता के लिए निरंतर अधिक है, जब आप एनोटेशन पूरी तरह से छोड़ देते हैं तो यह वही होता है।

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

सीएमटी लागू करने का सही तरीका क्या है?आपका नामित बीन्स में

@Stateless 
public class ValidateReportAction extends ReportAction { 

    @PersistenceContext(unitName = "MyPersistenceUnit") 
    private EntityManager em; 

    public String createReport() { 
     ReportBean report = new Report(); 
     // set report properties   
     em.persist(report) 
    } 
} 

फिर इस सेम इंजेक्षन (@EJB या @Inject उपयोग करते हुए):

सही तरीके से एक घटक मॉडल पहले से ही कंटेनर से CMT हो जाता है कि, एक राज्यविहीन सत्र सेम की तरह उपयोग करने के लिए है और इसका इस्तेमाल करें। वैकल्पिक रूप से इस बीन का नाम @Named का भी उपयोग किया जा सकता है, इसलिए इसे सीधे ईएल में उपयोग किया जा सकता है, लेकिन इसकी हमेशा अनुशंसा नहीं की जाती है।

@Stateless बीन स्कॉइंग (यह मूल रूप से 'आमंत्रण-स्कॉप्ड') की अनुमति नहीं देता है, लेकिन @Stateful मॉडल आपके मूल बीन के रूप में सत्र स्कॉप्ड किया जा सकता है। हालांकि, दी गई कार्यक्षमता के साथ इसे सत्र स्कॉप्ड होने की आवश्यकता नहीं है। यदि आप केवल इकाई प्रबंधक के लिए ऐसा किया, तो याद रखें:

  • इकाई प्रबंधक बहुत
  • यह जरूरी सुरक्षित थ्रेड नहीं है बनाने के लिए सस्ती है (आधिकारिक तौर पर यह नहीं है, लेकिन कुछ कार्यान्वयन में है)
  • स्टेटलेस बीन्स आमतौर पर पूल किए जाते हैं, जिससे ईएम स्वयं को http सत्र म्यूट में कैश करने की आवश्यकता होती है।

सीडीआई और जेटीए का उपयोग कर सीएमटी की तरह कुछ ऐसा करने के तरीके हैं, लेकिन यदि आप सच सीएमटी चाहते हैं तो इस पल के लिए यह एकमात्र तरीका है। स्टेटलेस, स्टेटफुल, सिंगलटन और व्यक्तिगत (सीडीआई) एनोटेशन में संचालित संदेश जैसे निश्चित घटक मॉडल तोड़ने की योजना है (http://java.net/jira/browse/EJB_SPEC देखें, और विशेष रूप से आपके प्रश्न Decoupling the @TransactionAttribute annotation from the EJB component model के लिए), लेकिन यह अभी तक नहीं हुआ है।

+0

एक और सही उत्तर, धन्यवाद! – nyxz

+0

@ अरजन तिजम्स, क्या यह उत्तर अभी भी मान्य है? – Ced

+0

@Ced Well, "@Transactional" अब एक अलग एनोटेशन के रूप में उपलब्ध है, इसलिए "अभी तक नहीं हुआ" अब हुआ है;) –

1

आप सही हैं, लेकिन आपके समाधान में आप एक नेस्टेड लेनदेन बनाते हैं, जो कॉलिंग संदर्भ से अलग हो जाता है। दुर्भाग्य से, मैं पारित करने के लिए एक समाधान खोजने के लिए सक्षम नहीं था जावा ईई 7 (CDI 1.1), अब आप CDI सेम में CMT सक्षम करने के लिए उपयोग कर सकते हैं @Transactional को यह

@Stateless 
public class ValidateReportAction extends ReportAction { 
... 

    @TransactionAttribute(TransactionAttributeType.REQUIRED) 
    public synchronized String createReport() { 
संबंधित मुद्दे