หน้าเว็บ

วันศุกร์ที่ 9 สิงหาคม พ.ศ. 2556

Config JPA EclipseLink(use Spring DATA) and Hibernate(NOT Spring DATA) in spring context xml : java

        บางครั้งเราอาจเจอเหตุการณ์บางเหตุการณ์ที่ต้องใช้ eclipseLink ร่วมกับ hibernate   อันนี้เลยเอามาแชร์เป็นประสบการณ์สำหรับทุกๆคนครับ  มาฟังปัญหาผมก่อนดีกว่าครับ  ว่าทำไมผมต้องทำแบบนี้

ปัญหา
        เนื่องจากในตอนแรกนั้น  ผมพัฒนาระบบโดยใช้ eclipseLink  แต่ทีนี้เกิดมีประเด็นว่า user อยากได้ full text search  ซึ่งเท่าที่คิด solution ออก  ก็มีเขียน lucene เพียวๆ กับใช้ hibernate ที่มี full text search ให้  ถ้าจะให้เขียน lucene ก็คงเหนื่อยน่าดู  ก็เลยเลือก hibernate เพราะว่าน่าจะง่ายกว่า  ผมก็เลยลองเปลี่ยนไปใช้ hibernate  แต่ปรากฏว่า  เกิดปัญหาเรื่อง lazy load in view ของ hibernate  แต่ eclipseLink ไม่พบปัญหานี้  ผมก็เลยหาทางแก้  ด้วยการ config hibernate ให้ open session in view  ตามที่คนอื่นๆ  บอก  แต่ก็ยังแก้ไม่ได้  ผมก็เลยคิดหาทางออกโดยการกลับไปใช้  eclipseLink เหมือนเดิม  ส่วนตัวที่ต้องการทำ full text search ก็ค่อยใช้ hibernate  จะได้ไม่ต้องมานั่ง test ระบบใหม่ทั้งหมด  ก็เลยทำให้เกิดกรณีการ ใช้งานร่วมกันระหว่าง eclipseLink และ hibernate เกิดขึ้น  โดยก่อนหน้านี้ eclipseLink ใช้ร่วมกับ spring data อยู่แล้ว  แต่มันมีข้อกำหนดของ spring data  ว่าใช้ได้แค่ 1 EntityManager เท่านั้น   ผมก็เลยให้ eclipseLink ใช้ spring data ต่อไป  ส่วน hibernate ซึ่งเอาไว้ทำเฉพาะ  full text search ก็ไม่ได้ใช้ spring data  ก็เลยสามารถแก้ปัญหานี้ได้ครับ   จึงทำให้เกิด บทความนี้ขึ้นมา  คือ  "การ config eclipseLink ร่วมกับ hibernate  โดย eclipseLink ใช้ spring data แต่ hibernate ไม่ได้ใช้"

ผมเลยเอาประสบการณ์นี้มาแชร์ให้กับทุกๆคนครับ

Resource Local Config
applicationContext-datasource.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:context="http://www.springframework.org/schema/context" 
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jee="http://www.springframework.org/schema/jee" 
       xmlns:aop="http://www.springframework.org/schema/aop" 
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-3.1.xsd
     http://www.springframework.org/schema/tx 
     http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
     http://www.springframework.org/schema/jee 
     http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
     http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
           http://www.springframework.org/schema/data/jpa
           http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

    <context:component-scan base-package="com.blogspot.na5cent" />
    <context:annotation-config />

    <tx:annotation-driven  transaction-manager="transactionManager" />
    
    <!-- 
        spring data use EclipseLink EntityManager (eclipseLinkEmf)
        spring data can use one EntityManager Only (EcelipsLink or Hibernate only not more than one)
    --> 
    <jpa:repositories base-package="com.blogspot.na5cent.repositories" entity-manager-factory-ref="eclipseLinkEmf" transaction-manager-ref="transactionManager"/>
    
    
    
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="eclipseLinkEmf"/>
    </bean>
    
    <!-- (JPA Transaction) .jpa.JpaTransactionManager -->
    <bean id="transactionManagerHibernate" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="hibernateEmf"/>
    </bean>
    
    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
        <property name="url" value="jdbc:oracle:thin:@YOUR_HOST:SERVICE_ID"/>
        <property name="username" value="USERNAME"/>
        <property name="password" value="PASSWORD"/>
    </bean>
</beans>
applicationContext-eclipseLink.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:context="http://www.springframework.org/schema/context" 
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jee="http://www.springframework.org/schema/jee" 
       xmlns:aop="http://www.springframework.org/schema/aop" 
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-3.1.xsd
     http://www.springframework.org/schema/tx 
     http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
     http://www.springframework.org/schema/jee 
     http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
     http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
           http://www.springframework.org/schema/data/jpa
           http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
    
    
    <bean id="eclipseLinkEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="ECLIPSELINK_PU"/>
        <property name="persistenceXmlLocation" value="classpath:META-INF/persistenceUnit.xml"/>
        <property name="dataSource" ref="dataSource" />
        <property name="jpaDialect">
            <bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect "/> 
        </property>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter "/>
        </property> 
    </bean>
</beans>
applicationContext-hibernate.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:context="http://www.springframework.org/schema/context" 
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jee="http://www.springframework.org/schema/jee" 
       xmlns:aop="http://www.springframework.org/schema/aop" 
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-3.1.xsd
     http://www.springframework.org/schema/tx 
     http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
     http://www.springframework.org/schema/jee 
     http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
     http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
           http://www.springframework.org/schema/data/jpa
           http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd">

    <bean id="hibernateEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="HIBERNATE_PU"/>
        <property name="persistenceXmlLocation" value="classpath:META-INF/persistenceUnit.xml" /> 
        <property name="dataSource" ref="dataSource" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="showSql" value="true"/>
                <property name="database" value="ORACLE" />
            </bean>
        </property>
    </bean>
</beans>
classpath:META-INF/persistenceUnit.xml
<?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">

  <!-- eclipseLink -->
  <persistence-unit name="ECLIPSELINK_PU" transaction-type="RESOURCE_LOCAL">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <non-jta-data-source>jdbc/hippo</non-jta-data-source>
    <class>com.blogspot.na5cent.model.Authorization</class>
    <class>com.blogspot.na5cent.model.BinaryDescriptor</class>
    <class>com.blogspot.na5cent.model.Document</class>
    <class>com.blogspot.na5cent.model.Folder</class>
    <class>com.blogspot.na5cent.model.Group</class>
    <class>com.blogspot.na5cent.model.Tag</class>
    <class>com.blogspot.na5cent.model.User</class>
    <exclude-unlisted-classes>true</exclude-unlisted-classes>
    <shared-cache-mode>NONE</shared-cache-mode>
    <validation-mode>NONE</validation-mode>
    <properties>
      <property name="eclipselink.logging.level" value="FINEST"/>
      <property name="eclipselink.logging.timestamp" value="false"/>
      <property name="eclipselink.logging.session" value="false"/>
      <property name="eclipselink.logging.thread" value="false"/>
      <property name="eclipselink.logging.parameters" value="true"/>
      <property name="eclipselink.cache.shared.default" value="false"/>
      <property name="eclipselink.target-server" value="SunAS9"/>
      <property name="eclipselink.weaving" value="static"/>
    </properties>
  </persistence-unit>

  <!-- hibernate -->
  <persistence-unit name="HIBERNATE_PU" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <non-jta-data-source>jdbc/hippo</non-jta-data-source>
    <class>com.blogspot.na5cent.model.BinaryFullTextEntry</class>
    <class>com.blogspot.na5cent.model.DocumentFullTextEntry</class>
    <exclude-unlisted-classes>true</exclude-unlisted-classes>
    <properties>
      <property name="hibernate.show_sql" value="true"/>
      <property name="hibernate.dialect" value="org.hibernate.dialect.OracleDialect"/>
      <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.SunONETransactionManagerLookup"/>
      <property name="hibernate.search.default.directory_provider" value="filesystem"/>
      <property name="hibernate.search.default.indexBase" value="${hibernate.search.default.indexBase}"/>
      <property name="hibernate.search.default.exclusive_index_use" value="false"/>
      <property name="hibernate.search.default.locking_strategy" value="native"/>
    </properties>
  </persistence-unit>
</persistence>

JTA(Java Transaction API) Config
applicationContext-datasource.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:context="http://www.springframework.org/schema/context" 
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jee="http://www.springframework.org/schema/jee" 
       xmlns:aop="http://www.springframework.org/schema/aop" 
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-3.1.xsd
     http://www.springframework.org/schema/tx 
     http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
     http://www.springframework.org/schema/jee 
     http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
     http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
           http://www.springframework.org/schema/data/jpa
           http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

    <context:component-scan base-package="com.blogspot.na5cent" />
    <context:annotation-config />

    <tx:annotation-driven />
    <!-- (JTA Transaction) .jta.JtaTransactionManager -->
    <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>

    <jpa:repositories base-package="com.blogspot.na5cent.repositories" entity-manager-factory-ref="eclipseLinkEmf"/>
   
    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
    <jee:jndi-lookup id="dataSource" jndi-name="JNDI_NAME" />
</beans>
applicationContext-eclipseLink.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:context="http://www.springframework.org/schema/context" 
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jee="http://www.springframework.org/schema/jee" 
       xmlns:aop="http://www.springframework.org/schema/aop" 
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-3.1.xsd
     http://www.springframework.org/schema/tx 
     http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
     http://www.springframework.org/schema/jee 
     http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
     http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
           http://www.springframework.org/schema/data/jpa
           http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
    
    
    <bean id="eclipseLinkEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="ECLIPSELINK_PU"/>
        <property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml"/>
        <property name="jpaDialect">
            <bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect " /> 
        </property>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter "/>
        </property> 
    </bean>
</beans>
applicationContext-hibernate.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:context="http://www.springframework.org/schema/context" 
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jee="http://www.springframework.org/schema/jee" 
       xmlns:aop="http://www.springframework.org/schema/aop" 
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-3.1.xsd
     http://www.springframework.org/schema/tx 
     http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
     http://www.springframework.org/schema/jee 
     http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
     http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
           http://www.springframework.org/schema/data/jpa
           http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd">

    <bean id="hibernateEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="HIBERNATE_PU"/>
        <property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" /> 
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="showSql" value="true"/>
                <property name="database" value="ORACLE" />
            </bean>
        </property>
    </bean>
</beans>
classpath:META-INF/persistenceUnit.xml
<?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">

  <!-- eclipseLink -->
  <persistence-unit name="ECELIPSELINK_PU" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>jdbc/hippo</jta-data-source>
    <class>com.blogspot.na5cent.model.Authorization</class>
    <class>com.blogspot.na5cent.model.BinaryDescriptor</class>
    <class>com.blogspot.na5cent.model.Document</class>
    <class>com.blogspot.na5cent.model.Folder</class>
    <class>com.blogspot.na5cent.model.Group</class>
    <class>com.blogspot.na5cent.model.Tag</class>
    <class>com.blogspot.na5cent.model.User</class>
    <exclude-unlisted-classes>true</exclude-unlisted-classes>
    <shared-cache-mode>NONE</shared-cache-mode>
    <validation-mode>NONE</validation-mode>
    <properties>
      <property name="eclipselink.logging.level" value="FINEST"/>
      <property name="eclipselink.logging.timestamp" value="false"/>
      <property name="eclipselink.logging.session" value="false"/>
      <property name="eclipselink.logging.thread" value="false"/>
      <property name="eclipselink.logging.parameters" value="true"/>
      <property name="eclipselink.cache.shared.default" value="false"/>
      <property name="eclipselink.target-server" value="SunAS9"/>
      <property name="eclipselink.weaving" value="static"/>
    </properties>
  </persistence-unit>

  <!-- hibernate -->
  <persistence-unit name="HIBERNATE_PU" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>jdbc/hippo</jta-data-source>
    <class>com.blogspot.na5cent.model.BinaryFullTextEntry</class>
    <class>com.blogspot.na5cent.model.DocumentFullTextEntry</class>
    <exclude-unlisted-classes>true</exclude-unlisted-classes>
    <properties>
      <property name="hibernate.hbm2ddl.auto" value="update"/>
      <property name="hibernate.show_sql" value="true"/>
      <property name="hibernate.dialect" value="org.hibernate.dialect.OracleDialect"/>
      <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.SunONETransactionManagerLookup"/>
      <property name="hibernate.search.default.directory_provider" value="filesystem"/>
      <property name="hibernate.search.default.indexBase" value="${hibernate.search.default.indexBase}"/>
      <property name="hibernate.search.default.exclusive_index_use" value="false"/>
      <property name="hibernate.search.default.locking_strategy" value="native"/>
    </properties>
  </persistence-unit>
</persistence>

ส่วน Service ที่ต้องใช้ Hibernate เราก็ Inject EntityManager เข้ามา จากนั้นก็กำหนด PersistenceUnitName เป็น Hibernate(HIBERNATE_PU) ครับ ดังนี้
...
...
...
@Service
@Transactional(propagation = Propagation.REQUIRED)
public class FullTextSearchServiceImpl implements FullTextSearchService {

    private static final String HTML_START = "<span class=\"fulltext-highlight\">";
    private static final String HTML_END = "</span>";
    private static final String SEARCH_ON_FIELD = "fullText";
    private static final Version LUCENE_VERSION = Version.LUCENE_36;

    @PersistenceContext(unitName = "HIBERNATE_PU") //****************
    private EntityManager entityManager;

    @Override
    public PageResult<FullTextSearchResult> search(String keyword, int start, int pageSize, Class<? extends FullTextEntry> clazz) throws Exception {
        FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
        SearchFactory searchFactory = fullTextEntityManager.getSearchFactory();
        //
        QueryBuilder queryBuilder = searchFactory.buildQueryBuilder()
                .forEntity(clazz)
                .get();

        ...
        ...
        ...
    }
}
หวังว่าคงเป็นประโยชน์สำหรับบางคนน่ะครับ

ไม่มีความคิดเห็น:

แสดงความคิดเห็น