PostgreSQL
 sql >> डेटाबेस >  >> RDS >> PostgreSQL

मैं जेटीए लेनदेन की घटनाओं को कैसे रोक सकता हूं और लेनदेन से जुड़े वर्तमान EntityManager का संदर्भ प्राप्त कर सकता हूं

इसका उत्तर इस पोस्ट में मेरे द्वारा तुरंत दिया गया था, लेकिन इस तथ्य को छिपाते हुए कि हमने इसे दूर करने के लिए विभिन्न रणनीतियों की कोशिश करते हुए दो सप्ताह से अधिक समय बिताया। तो, यहाँ हमारा अंतिम कार्यान्वयन है जिसका हमने उपयोग करने का निर्णय लिया है।

मूल विचार: javax.persistence.spi.PersistenceProvider . का अपना स्वयं का कार्यान्वयन बनाएं हाइबरनेट द्वारा दिए गए एक का विस्तार करके। सभी प्रभावों के लिए, यह एकमात्र बिंदु है जहां आपका कोड हाइबरनेट या किसी अन्य विक्रेता विशिष्ट कार्यान्वयन से जुड़ा होगा।

public class MyHibernatePersistenceProvider extends org.hibernate.jpa.HibernatePersistenceProvider {

    @Override
    public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map properties) {
        return new EntityManagerFactoryWrapper(super.createContainerEntityManagerFactory(info, properties));
    }

}

विचार हाइबरनेट के EntityManagerFactory . के संस्करणों को लपेटने का है और इकाई प्रबंधक अपने स्वयं के कार्यान्वयन के साथ। इसलिए आपको ऐसी कक्षाएं बनाने की ज़रूरत है जो इन इंटरफेस को लागू करें और विक्रेता विशिष्ट कार्यान्वयन को अंदर रखें।

यह EntityManagerFactoryWrapper है

public class EntityManagerFactoryWrapper implements EntityManagerFactory {

    private EntityManagerFactory emf;

    public EntityManagerFactoryWrapper(EntityManagerFactory originalEMF) {
        emf = originalEMF;
    }

    public EntityManager createEntityManager() {
        return new EntityManagerWrapper(emf.createEntityManager());
    }

    // Implement all other methods for the interface
    // providing a callback to the original emf.

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

public class EntityManagerWrapper implements EntityManager {

    private EntityManager em;
    private Principal principal;

    public EntityManagerWrapper(EntityManager originalEM) {
        em = originalEM;
    }

    public void setAuditVariables() {
        String userid = getUserId();
        String ipaddr = getUserAddr();
        String sql = "SET LOCAL application.userid='"+userid+"'; SET LOCAL application.ipaddr='"+ipaddr+"'";
        em.createNativeQuery(sql).executeUpdate();
    }

    protected String getUserAddr() {
        HttpServletRequest httprequest = CDIBeanUtils.getBean(HttpServletRequest.class);
        String ipaddr = "";
        if ( httprequest != null ) {
            ipaddr = httprequest.getRemoteAddr();
        }
        return ipaddr;
    }

    protected String getUserId() {
        String userid = "";
        // Try to look up a contextual reference
        if ( principal == null ) {
            principal = CDIBeanUtils.getBean(Principal.class);
        }

        // Try to assert it from CAS authentication
        if (principal == null || "anonymous".equalsIgnoreCase(principal.getName())) {
            if (AssertionHolder.getAssertion() != null) {
                principal = AssertionHolder.getAssertion().getPrincipal();
            }
        }
        if ( principal != null ) {
            userid = principal.getName();
        }
        return userid;
    }

    @Override
    public void persist(Object entity) {
        if ( em.isJoinedToTransaction() ) {
            setAuditVariables();
        }
        em.persist(entity);
    }

    @Override
    public <T> T merge(T entity) {
        if ( em.isJoinedToTransaction() ) {
            setAuditVariables();
        }
        return em.merge(entity);
    }

    @Override
    public void remove(Object entity) {
        if ( em.isJoinedToTransaction() ) {
            setAuditVariables();
        }
        em.remove(entity);
    }

    // Keep implementing all methods that can change
    // entities so you can setAuditVariables() before
    // the changes are applied.
    @Override
    public void createNamedQuery(.....

नकारात्मक पक्ष: इंटरसेप्शन क्वेश्चन (सेट लोकल) एक ट्रांजैक्शन के अंदर कई बार चलने की संभावना है, खासकर अगर सिंगल सर्विस कॉल पर कई स्टेटमेंट दिए गए हों। परिस्थितियों को देखते हुए, हमने इसे इस तरह से रखने का फैसला किया क्योंकि यह PostgreSQL के लिए मेमोरी कॉल में एक साधारण SET LOCAL है। चूंकि इसमें कोई टेबल शामिल नहीं है, हम प्रदर्शन हिट के साथ जी सकते हैं।

अब बस हाइबरनेट के हठ प्रदाता को persistence.xml . के अंदर बदलें :

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
             version="2.1">
<persistence-unit name="petstore" transaction-type="JTA">
        <provider>my.package.HibernatePersistenceProvider</provider>
        <jta-data-source>java:app/jdbc/exemplo</jta-data-source>
        <properties>
            <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
        </properties>
</persistence-unit>

एक साइड नोट के रूप में, यह CDIBeanUtils है जिसे हमें कुछ विशेष अवसरों पर बीन मैनेजर की मदद करनी होती है। इस मामले में, हम इसका उपयोग HttpServletRequest और प्रिंसिपल के संदर्भ को देखने के लिए कर रहे हैं।

public class CDIBeanUtils {

    public static <T> T getBean(Class<T> beanClass) {

        BeanManager bm = CDI.current().getBeanManager();

        Iterator<Bean<?>> ite = bm.getBeans(beanClass).iterator();
        if (!ite.hasNext()) {
            return null;
        }
        final Bean<T> bean = (Bean<T>) ite.next();
        final CreationalContext<T> ctx = bm.createCreationalContext(bean);
        final T t = (T) bm.getReference(bean, beanClass, ctx);
        return t;
    }

}

निष्पक्ष होने के लिए, यह लेनदेन की घटनाओं को बिल्कुल बाधित नहीं कर रहा है। लेकिन हम लेन-देन के अंदर आवश्यक कस्टम प्रश्नों को शामिल करने में सक्षम हैं।

उम्मीद है कि यह दूसरों को उस दर्द से बचने में मदद कर सकता है जिससे हम गुज़रे हैं।




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PostgreSQL के स्कीमा और रेल का उपयोग करके एक बहु-किरायेदार एप्लिकेशन बनाना

  2. शब्द को शांत करने का सबसे आसान तरीका पोस्टग्रेएसक्यूएल में अनुक्रमित नोटिस होने के लिए बहुत लंबा है

  3. psycopg2 कनेक्शन के बाद कोई टेबल नहीं ढूँढ सकता

  4. अन्य कॉलम के आधार पर एक कॉलम में एक वास्तविक संख्या डालें पुराने INSERTs

  5. टेबल कॉलम पर पोस्टग्रेज JSON फ़ंक्शंस का उपयोग करना