>  기사  >  Java  >  Spring 다중 데이터 소스 구성에 대한 심층적 이해

Spring 다중 데이터 소스 구성에 대한 심층적 이해

高洛峰
高洛峰원래의
2017-01-24 10:35:461220검색

우리는 프로젝트, 특히 데이터 동기화나 예약된 작업과 같은 프로젝트에서 여러 데이터 소스 문제에 자주 직면합니다. 다중 데이터 소스의 가장 큰 골칫거리는 다중 데이터 소스를 구성하는 것이 아니라 데이터 소스를 유연하고 동적으로 전환하는 방법입니다. 예를 들어, Spring 및 Hibernate 프레임워크 프로젝트에서는 종종 spring 구성에서 데이터베이스에 연결하도록 dataSource를 구성한 다음 이를 sessionFactory에 바인딩한 다음 dao 레이어 코드에서 sessionFactory를 지정하여 데이터베이스 작업을 수행합니다.

Spring 다중 데이터 소스 구성에 대한 심층적 이해

위 그림과 같이 각 블록을 지정하여 연결하는데, 데이터 소스가 여러 개인 경우 아래 그림과 같이만 가능합니다.

Spring 다중 데이터 소스 구성에 대한 심층적 이해

Dao 레이어 코드에는 두 개의 SessionFactory가 작성되어 있는 것을 볼 수 있는데, 향후 다른 데이터 소스가 있을 경우 코드를 변경하여 추가해야 할 것입니다. 분명히 이것은 열기 및 닫기 원칙을 준수하지 않습니다.

그러면 올바른 접근 방식은

Spring 다중 데이터 소스 구성에 대한 심층적 이해

코드는 다음과 같습니다.

1.

<?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:aop="http://www.springframework.org/schema/aop"
  xmlns:cache="http://www.springframework.org/schema/cache"
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee"
  xmlns:jms="http://www.springframework.org/schema/jms" xmlns:lang="http://www.springframework.org/schema/lang"
  xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:oxm="http://www.springframework.org/schema/oxm"
  xmlns:p="http://www.springframework.org/schema/p" xmlns:task="http://www.springframework.org/schema/task"
  xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
  http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd  
  http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.1.xsd  
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd  
  http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-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/jms http://www.springframework.org/schema/jms/spring-jms-3.1.xsd  
  http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.1.xsd  
  http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd  
  http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.1.xsd  
  http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-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/util http://www.springframework.org/schema/util/spring-util-3.1.xsd"> 
  
  <context:annotation-config /> 
  
  <context:component-scan base-package="com"></context:component-scan> 
  
  <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
    <property name="locations"> 
      <list> 
        <value>classpath:com/resource/config.properties</value> 
      </list> 
    </property> 
  </bean> 
  
  <bean id="dataSourceOne" class="com.mchange.v2.c3p0.ComboPooledDataSource"
    destroy-method="close"> 
    <property name="driverClass" value="${dbOne.jdbc.driverClass}" /> 
    <property name="jdbcUrl" value="${dbOne.jdbc.url}" /> 
    <property name="user" value="${dbOne.jdbc.user}" /> 
    <property name="password" value="${dbOne.jdbc.password}" /> 
    <property name="initialPoolSize" value="${dbOne.jdbc.initialPoolSize}" /> 
    <property name="minPoolSize" value="${dbOne.jdbc.minPoolSize}" /> 
    <property name="maxPoolSize" value="${dbOne.jdbc.maxPoolSize}" /> 
  </bean> 
  
  <bean id="dataSourceTwo" class="com.mchange.v2.c3p0.ComboPooledDataSource"
    destroy-method="close"> 
    <property name="driverClass" value="${dbTwo.jdbc.driverClass}" /> 
    <property name="jdbcUrl" value="${dbTwo.jdbc.url}" /> 
    <property name="user" value="${dbTwo.jdbc.user}" /> 
    <property name="password" value="${dbTwo.jdbc.password}" /> 
    <property name="initialPoolSize" value="${dbTwo.jdbc.initialPoolSize}" /> 
    <property name="minPoolSize" value="${dbTwo.jdbc.minPoolSize}" /> 
    <property name="maxPoolSize" value="${dbTwo.jdbc.maxPoolSize}" /> 
  </bean> 
  
  <bean id="dynamicDataSource" class="com.core.DynamicDataSource"> 
    <property name="targetDataSources"> 
      <map key-type="java.lang.String"> 
        <entry value-ref="dataSourceOne" key="dataSourceOne"></entry> 
        <entry value-ref="dataSourceTwo" key="dataSourceTwo"></entry> 
      </map> 
    </property> 
    <property name="defaultTargetDataSource" ref="dataSourceOne"> 
    </property> 
  </bean> 
  
  <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> 
    <property name="dataSource" ref="dynamicDataSource" /> 
    <property name="hibernateProperties"> 
      <props> 
        <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> 
        <prop key="hibernate.current_session_context_class">org.springframework.orm.hibernate4.SpringSessionContext</prop> 
        <prop key="hibernate.show_sql">false</prop> 
        <prop key="hibernate.format_sql">true</prop> 
        <prop key="hbm2ddl.auto">create</prop> 
      </props> 
    </property> 
    <property name="packagesToScan"> 
      <list> 
        <value>com.po</value> 
      </list> 
    </property> 
  </bean> 
  
  <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> 
    <property name="sessionFactory" ref="sessionFactory" /> 
  </bean> 
  
  <aop:config> 
    <aop:pointcut id="transactionPointCut" expression="execution(* com.dao..*.*(..))" /> 
    <aop:advisor advice-ref="txAdvice" pointcut-ref="transactionPointCut" /> 
  </aop:config> 
  
  <tx:advice id="txAdvice" transaction-manager="transactionManager"> 
    <tx:attributes> 
      <tx:method name="add*" propagation="REQUIRED" /> 
      <tx:method name="save*" propagation="REQUIRED" /> 
      <tx:method name="update*" propagation="REQUIRED" /> 
      <tx:method name="delete*" propagation="REQUIRED" /> 
      <tx:method name="*" read-only="true" /> 
    </tx:attributes> 
  </tx:advice> 
  
  <aop:config> 
    <aop:aspect id="dataSourceAspect" ref="dataSourceInterceptor"> 
      <aop:pointcut id="daoOne" expression="execution(* com.dao.one.*.*(..))" /> 
      <aop:pointcut id="daoTwo" expression="execution(* com.dao.two.*.*(..))" /> 
      <aop:before pointcut-ref="daoOne" method="setdataSourceOne" /> 
      <aop:before pointcut-ref="daoTwo" method="setdataSourceTwo" /> 
    </aop:aspect> 
  </aop:config> 
</beans>

2. DynamicDataSource.class

package com.core; 
  
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; 
  
public class DynamicDataSource extends AbstractRoutingDataSource{ 
  
  @Override
  protected Object determineCurrentLookupKey() { 
    return DatabaseContextHolder.getCustomerType();  
  } 
  
}

3. DatabaseContextHolder.class

package com.core; 
  
public class DatabaseContextHolder { 
  
  private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); 
  
  public static void setCustomerType(String customerType) { 
    contextHolder.set(customerType); 
  } 
  
  public static String getCustomerType() { 
    return contextHolder.get(); 
  } 
  
  public static void clearCustomerType() { 
    contextHolder.remove(); 
  } 
}

4. DataSourceInterceptor.class

package com.core; 
  
import org.aspectj.lang.JoinPoint; 
import org.springframework.stereotype.Component; 
  
@Component
public class DataSourceInterceptor { 
  
  public void setdataSourceOne(JoinPoint jp) { 
    DatabaseContextHolder.setCustomerType("dataSourceOne"); 
  } 
    
  public void setdataSourceTwo(JoinPoint jp) { 
    DatabaseContextHolder.setCustomerType("dataSourceTwo"); 
  } 
}

5. >

package com.po; 
  
import javax.persistence.Column; 
import javax.persistence.Entity; 
import javax.persistence.Id; 
import javax.persistence.Table; 
  
@Entity
@Table(name = "BTSF_BRAND", schema = "hotel") 
public class Brand { 
  
  private String id; 
  private String names; 
  private String url; 
  
  @Id
  @Column(name = "ID", unique = true, nullable = false, length = 10) 
  public String getId() { 
    return this.id; 
  } 
  
  public void setId(String id) { 
    this.id = id; 
  } 
  
  @Column(name = "NAMES", nullable = false, length = 50) 
  public String getNames() { 
    return this.names; 
  } 
  
  public void setNames(String names) { 
    this.names = names; 
  } 
  
  @Column(name = "URL", length = 200) 
  public String getUrl() { 
    return this.url; 
  } 
  
  public void setUrl(String url) { 
    this.url = url; 
  } 
}
package com.po;  
import javax.persistence.Column; 
import javax.persistence.Entity; 
import javax.persistence.Id; 
import javax.persistence.Table; 
  
@Entity
@Table(name = "CITY", schema = "car") 
public class City { 
  
  private Integer id; 
    
  private String name; 
  
  @Id
  @Column(name = "ID", unique = true, nullable = false) 
  public Integer getId() { 
    return id; 
  } 
  
  public void setId(Integer id) { 
    this.id = id; 
  } 
  
  @Column(name = "NAMES", nullable = false, length = 50) 
  public String getName() { 
    return name; 
  } 
  
  public void setName(String name) { 
    this.name = name; 
  } 
}

6. BrandDaoImpl.class

package com.dao.one; 
  
import java.util.List; 
  
import javax.annotation.Resource; 
  
import org.hibernate.Query; 
import org.hibernate.SessionFactory; 
import org.springframework.stereotype.Repository; 
  
import com.po.Brand; 
  
@Repository
public class BrandDaoImpl implements IBrandDao { 
  
  @Resource
  protected SessionFactory sessionFactory; 
  
  @SuppressWarnings("unchecked") 
  @Override
  public List<Brand> findAll() { 
    String hql = "from Brand"; 
    Query query = sessionFactory.getCurrentSession().createQuery(hql); 
    return query.list(); 
  } 
}

7. CityDaoImpl.class

package com.dao.two;
  
import java.util.List;
  
import javax.annotation.Resource;
  
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.springframework.stereotype.Repository;
  
import com.po.City;
  
@Repository
public class CityDaoImpl implements ICityDao {
  
  @Resource
  private SessionFactory sessionFactory;
  
  @SuppressWarnings("unchecked")
  @Override
  public List<City> find() {
    String hql = "from City";
    Query query = sessionFactory.getCurrentSession().createQuery(hql);
    return query.list();
  }
}

aop를 사용하여 데이터 소스를 동적으로 변경하세요. 데이터 소스를 추가해야 하는 경우 applicationContext 구성 파일에 aop 구성을 추가하고 새 DataSourceInterceptor를 생성하기만 하면 됩니다. 코드를 변경하지 않고.

위 내용은 이 글의 전체 내용입니다. 모든 분들의 학습에 도움이 되기를 바랍니다. 또한 모든 분들이 PHP 중국어 웹사이트를 지지해주시기를 바랍니다.

Spring 다중 데이터 소스 구성 관련 기사를 더 자세히 이해하려면 PHP 중국어 웹 사이트를 주목하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.