此文几处有引用别人博客内容,如有侵权表示歉意!
web项目中可能会遇到多数据源的情况,这个时候我们需要在不同的情况下使用不同的数据源对不同的数据库进行访问,最典型的案例是数据的读写分离。
多数据源的设计思路:
多数据源的具体配置步骤:
- spring配置文件中,配置不同的数据源
<!-- 数据源1 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.pwd}"/>
</bean>
<!-- 数据源2 -->
<bean id="dataSource2" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url2}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.pwd}"/>
</bean>
2.实现DynamicDataSource类 并继承org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource类,重写determineCurrentLookupKey()方法:
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DatabaseContextHolder.getCustomerType();
}
}
- 实现DatabaseContextHolder类,内部实现ThreadLocal 类来保证线程安全
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.配置数据源集合dynamicDataSource
<bean id="dynamicDataSource" class="com.laie.pa.common.dao.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry value-ref="dataSource" key="dataSource"></entry>
<entry value-ref="dataSource2" key="dataSource2"></entry>
</map>
</property>
<!—配置默认数据源 -->
<property name="defaultTargetDataSource" ref="dataSource"></property>
</bean>
- 配置数据源切换
5.1 实现DataSourceInterceptor 类并配置Bean
import org.aspectj.lang.JoinPoint;
import org.springframework.stereotype.Component;
@Component
public class DataSourceInterceptor {
public void setdataSourceOne(JoinPoint jp) {
DatabaseContextHolder.setCustomerType("dataSource");
}
public void setdataSourceTwo(JoinPoint jp) {
DatabaseContextHolder.setCustomerType("dataSource2");
}
}
Spring.xml 文件配置此Bean
<bean id="dataSourceInterceptor" class="com.laie.pa.common.dao.DataSourceInterceptor" />
5.2 配置AOP 实现数据源切换
<aop:config>
<aop:aspect id="dataSourceAspect" ref="dataSourceInterceptor">
<aop:pointcut id="daoOne" expression="execution(* com.laie.pa.action.*.*(..))" />
<aop:pointcut id="daoTwo" expression="execution(* com.laie.pa.action2.*.*(..))" />
<aop:before pointcut-ref="daoOne" method="setdataSourceOne" />
<aop:before pointcut-ref="daoTwo" method="setdataSourceTwo" />
</aop:aspect>
</aop:config>
注:实现切换利用了aop中配置了执行的包下的所有方法使用不同的数据源。