복붙노트

[SPRING] 두 개 이상의 데이터 소스를 사용할 때 Spring의 다중 Entity Manager 문제

SPRING

두 개 이상의 데이터 소스를 사용할 때 Spring의 다중 Entity Manager 문제

두 개의 다른 데이터베이스에 해당하는 applicationContext.xml에 두 개의 엔티티 관리자가 있습니다. entityManager1을 사용하여 database1을 쉽게 쿼리 할 수 ​​있지만 entityManager2를 사용하여 database2에 액세스하려고하면 결과가 표시되지 않습니다. 나는 Spring + Hibernate + JPA를 사용하고있다.

다음은 내 ApplicationContext.xml입니다.

    <?xml version="1.0" encoding="UTF-8"?>

    <beans default-autowire="byName"
     xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:tx="http://www.springframework.org/schema/tx"
     xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

 <bean
  class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />


 <bean id="entityManagerFactory"
  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="dataSource" ref="dataSource" />
  <property name="jpaVendorAdapter">
   <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    <property name="database" value="INFORMIX" />
    <property name="showSql" value="true" />
   </bean>
  </property>
  <property name="persistenceUnitManager" ref="persistenceUnitManager" />
  <property name="persistenceUnitName" value="PU1" />
 </bean>



 <bean id="entityManagerFactory2"
  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="dataSource" ref="dataSource2" />
  <property name="jpaVendorAdapter">
   <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    <property name="database" value="INFORMIX" />
    <property name="showSql" value="true" />
   </bean>
  </property>
  <property name="persistenceUnitManager" ref="persistenceUnitManager" />
  <property name="persistenceUnitName" value="PU2" />
 </bean>



 <!-- Data Sources -->

 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
  destroy-method="close">
  <property name="driverClassName" value="com.ibm.db2.jcc.DB2Driver" />
  <property name="url"
   value="jdbc:db2://HOST_NAME:PORT_NO/DB_NAME:INFORMIXSERVER=SERVER_NAME;DELIMIDENT=y;" />
  <property name="username" value="username" />
  <property name="password" value="password" />
  <property name="minIdle" value="2" />
 </bean>

 <bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource"
  destroy-method="close">
  <property name="driverClassName" value="com.ibm.db2.jcc.DB2Driver" />
  <property name="url"
   value="jdbc:db2://HOST_NAME:PORT_NO/DB_NAME2:INFORMIXSERVER=SERVER_NAME;DELIMIDENT=y;" />
  <property name="username" value="username" />
  <property name="password" value="password" />
  <property name="minIdle" value="2" />
 </bean>

 <bean
  class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"
  lazy-init="false">
  <property name="targetObject" ref="dataSource" />
  <property name="targetMethod" value="addConnectionProperty" />
  <property name="arguments">
   <list>
    <value>characterEncoding</value>
    <value>UTF-8</value>
   </list>
  </property>
 </bean>

 <bean
  class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"
  lazy-init="false">
  <property name="targetObject" ref="dataSource2" />
  <property name="targetMethod" value="addConnectionProperty" />
  <property name="arguments">
   <list>
    <value>characterEncoding</value>
    <value>UTF-8</value>
   </list>
  </property>
 </bean>

 <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
  scope="prototype">
  <property name="dataSource" ref="dataSource" />
 </bean>



 <bean id="persistenceUnitManager"
  class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
  <property name="persistenceXmlLocations">
   <list>
    <value>classpath*:META-INF/persistence.xml</value>
    <value>classpath*:META-INF/persistence2.xml</value>
   </list>
  </property>
  <property name="dataSources">
   <map>
    <entry key="localDataSource" value-ref="dataSource" />
    <entry key="dataSource2" value-ref="dataSource2" />
   </map>
  </property>
  <property name="defaultDataSource" ref="dataSource" />
 </bean>



 <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
  <property name="entityManagerFactory" ref="entityManagerFactory" />
 </bean>

 <bean id="transactionManager2" class="org.springframework.orm.jpa.JpaTransactionManager">
  <property name="entityManagerFactory" ref="entityManagerFactory2" />
 </bean>

 <tx:annotation-driven transaction-manager="transactionManager" />
 <tx:annotation-driven transaction-manager="transactionManager2" />

 <!-- MORE Action and DAO beans -->


</beans>

이것은 enityManager1에서 잘 작동하는 서비스 레이어 코드입니다.

  @Transactional
    public class StatesDAO implements IStatesDAO {
 private EntityManager em;

 @PersistenceContext(unitName = "PU1")
 public void setEntityManager(EntityManager em) {
  this.em = em;
 }

 private EntityManager getEntityManager() {
  return em;
 }

 @SuppressWarnings("unchecked")
 public List<States> findAll() {
  logger.info("finding all States instances");
  try {
   final String queryString = "select model from States model";

   Query query = getEntityManager().createQuery(queryString);
   return query.getResultList();

  } catch (RuntimeException re) {
   throw re;
  }

 }

    }

내 두 persistence.xml 파일은 다음과 같습니다.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.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_1_0.xsd">
 <persistence-unit name="PU1" transaction-type="RESOURCE_LOCAL">
  <provider>org.hibernate.ejb.HibernatePersistence</provider>
  <class>com.jpa.entity.States</class>
 </persistence-unit>
</persistence>

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.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_1_0.xsd">
 <persistence-unit name="PU2" transaction-type="RESOURCE_LOCAL">
  <provider>org.hibernate.ejb.HibernatePersistence</provider>
  <class>com.jpa.other.entity.States</class>
 </persistence-unit>
</persistence>

내 서비스 계층을 변경하면 (아래 그림 참조) 결과가 없습니다. 기본적으로 목록의 크기는 0입니다.

@Transactional
public class StatesDAO implements IStatesDAO {
private EntityManager em;

@PersistenceContext(unitName = "PU2")
public void setEntityManager(EntityManager em) {
    this.em = em;
}

private EntityManager getEntityManager() {
    return em;
}

@SuppressWarnings("unchecked")
public List<com.jpa.other.entity.States> findAll() {
    logger.info("finding all States instances");
    try {
        final String queryString = "select model from States model";

        Query query = getEntityManager().createQuery(queryString);
        return query.getResultList();

    } catch (RuntimeException re) {
        throw re;
    }

}

}

그래서 기본적으로 내가 볼 수있는 것은 두 개의 엔티티 (상태)가 정확히 같은 구조이고 서로 구별하기 위해 별도의 패키지에 넣었습니다

내 지식에 따르면 나는 여기에 어떤 미친 짓을하지 않고 있지만 여전히 작동하지 않는 것 같습니다. 이 문제는 어떻게 발생하며 어떻게 해결할 수 있습니까?

후속 조치 : 내가 언급 한 것을 잊어 버린 한 가지 사실은 두 개의 서로 다른 데이터베이스가 있지만 데이터베이스 서버 이름이 동일하다는 것입니다. 나는 이것이 유용한 정보가 될지 모르겠다. 그래서 그것을 공유하는 것을 생각했다.

이것은 지금 내가 얻고있는 예외 다 :

16:24:44,732 INFO [STDOUT] Hibernate: select state0_.state as col_0_0_ from states state0_ 
16:24:44,753 WARN [JDBCExceptionReporter] SQL Warning: 36106, SQLState: 01I01 
16:24:44,753 WARN [JDBCExceptionReporter] IDS SQL Warning: SQLCODE=36106, SQLSTATE=01I01, SQLERRMC=0;819;informix;;IDS/NT32;1;1;0;819;0;, DRIVER=4.7.85 

해결법

  1. ==============================

    1.똑같은 문제를 겪었지만 여러 개의 Hibernate 세션 팩토리들 : 동일한 구조를 가진 2 개의 DB들, 2 개의 동일한 DAO 세트를 갖고 싶지 않았습니다. 내 경험이 최대 절전 모드 였을 때, 동일한 솔루션 : Spring의 AbstractRoutingDataSource. ThreadLocal에 설정된 값에 따라 런타임에 사용할 데이터 소스를 결정하도록 앱을 구성 할 수 있습니다. 소개는 http://blog.springsource.com/2007/01/23/dynamic-datasource-routing/을 참조하십시오. 무슨 일이 일어나는지는 공장에서 dataSource ref가 하드 코딩 된 dataSource 빈이 아니라 AbstractRoutingDataSource를 가리킬 것이라는 것입니다. 스레드 당 토글을 설정하려면 @Aspect를 사용하여 어느 DB를 조회해야하는지 결정하십시오.

    똑같은 문제를 겪었지만 여러 개의 Hibernate 세션 팩토리들 : 동일한 구조를 가진 2 개의 DB들, 2 개의 동일한 DAO 세트를 갖고 싶지 않았습니다. 내 경험이 최대 절전 모드 였을 때, 동일한 솔루션 : Spring의 AbstractRoutingDataSource. ThreadLocal에 설정된 값에 따라 런타임에 사용할 데이터 소스를 결정하도록 앱을 구성 할 수 있습니다. 소개는 http://blog.springsource.com/2007/01/23/dynamic-datasource-routing/을 참조하십시오. 무슨 일이 일어나는지는 공장에서 dataSource ref가 하드 코딩 된 dataSource 빈이 아니라 AbstractRoutingDataSource를 가리킬 것이라는 것입니다. 스레드 당 토글을 설정하려면 @Aspect를 사용하여 어느 DB를 조회해야하는지 결정하십시오.

  2. from https://stackoverflow.com/questions/3731016/multiple-entity-manager-issue-in-spring-when-using-more-than-one-datasource by cc-by-sa and MIT license