关键配置:AbstractRoutingDataSource
使用这个动态管理DataSource的数据源就可以实现动态切换数据源了,亲测可用。
给出部分配置代码:
spring-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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<description>数据源配置</description>
<!-- 数据源模板 -->
<bean id="dataSourceTemplate"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"
value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- 数据源,Tomcat-jdbc实现 -->
<bean id="dataSource"
class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
<!-- 通过引用加载数据库信息,否则会报找不到数据库驱动的错误 -->
<property name="dataSource" ref="dataSourceTemplate" />
<!-- (int) 初始化连接: 连接池启动时创建的初始化连接数量 -->
<property name="initialSize" value="${jdbc.initialPoolSize}" />
<property name="minIdle" value="${jdbc.minPoolSize}" />
<property name="maxIdle" value="${jdbc.maxPoolSize}" />
<property name="maxActive" value="${jdbc.maxPoolSize}" />
<property name="maxWait" value="600" />
<property name="removeAbandoned" value="true" />
<!-- (int) 泄露的连接可以被删除的超时值, 单位秒应设置为应用中查询执行最长的时间 -->
<property name="removeAbandonedTimeout" value="600" />
<property name="validationQuery" value="select 1" />
<property name="validationInterval" value="30000" />
<!-- (boolean) 连接池创建的连接的默认的auto-commit 状态,driver default -->
<property name="defaultAutoCommit" value="true" />
<!-- 验证失败时,是否将连接从池中丢弃 -->
<property name="testWhileIdle" value="true" />
<property name="timeBetweenEvictionRunsMillis"
value="1200000" />
<!-- 连接池中连接可空闲的时间(毫秒,5分钟) -->
<property name="minEvictableIdleTimeMillis" value="1800000" />
<!-- 在每次空闲连接回收器线程(如果有)运行时检查的连接数量 -->
<property name="numTestsPerEvictionRun" value="5" />
</bean>
<!-- 数据源模板2 -->
<bean id="dataSourceTemplate2"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"
value="${jdbc2.driverClassName}" />
<property name="url" value="${jdbc2.url}" />
<property name="username" value="${jdbc2.username}" />
<property name="password" value="${jdbc2.password}" />
</bean>
<!-- 数据源2,Tomcat-jdbc实现 -->
<bean id="dataSource2"
class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
<!-- 通过引用加载数据库信息,否则会报找不到数据库驱动的错误 -->
<property name="dataSource" ref="dataSourceTemplate2" />
<!-- (int) 初始化连接: 连接池启动时创建的初始化连接数量 -->
<property name="initialSize" value="${jdbc2.initialPoolSize}" />
<property name="minIdle" value="${jdbc2.minPoolSize}" />
<property name="maxIdle" value="${jdbc2.maxPoolSize}" />
<property name="maxActive" value="${jdbc2.maxPoolSize}" />
<property name="maxWait" value="600" />
<property name="removeAbandoned" value="true" />
<!-- (int) 泄露的连接可以被删除的超时值, 单位秒应设置为应用中查询执行最长的时间 -->
<property name="removeAbandonedTimeout" value="600" />
<property name="validationQuery" value="select 1" />
<property name="validationInterval" value="30000" />
<!-- (boolean) 连接池创建的连接的默认的auto-commit 状态,driver default -->
<property name="defaultAutoCommit" value="true" />
<!-- 验证失败时,是否将连接从池中丢弃 -->
<property name="testWhileIdle" value="true" />
<property name="timeBetweenEvictionRunsMillis"
value="1200000" />
<!-- 连接池中连接可空闲的时间(毫秒,5分钟) -->
<property name="minEvictableIdleTimeMillis" value="1800000" />
<!-- 在每次空闲连接回收器线程(如果有)运行时检查的连接数量 -->
<property name="numTestsPerEvictionRun" value="5" />
</bean>
<!-- 路由数据源配置 -->
<bean id="dynamicDataSource"
class="com.szhis.frsoft.common.datasource.DynamicDataSource">
<!-- 默认数据源 -->
<property name="defaultTargetDataSource" ref="dataSource"></property>
<!-- 数据源集合 -->
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="first" value-ref="dataSource" />
<entry key="second" value-ref="dataSource2" />
</map>
</property>
</bean>
</beans>
spring-dao.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:jpa="http://www.springframework.org/schema/data/jpa"
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/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd">
<description>持久层配置</description>
<!-- jpa 实体工厂 -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<!-- 指定路由数据源,这个很关键 -->
<property name="dataSource" ref="dynamicDataSource" />
<property name="packagesToScan"
value="com.szhis.frsoft.entity" />
<property name="persistenceProvider">
<bean class="org.hibernate.jpa.HibernatePersistenceProvider"></bean>
</property>
<property name="jpaDialect">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"></bean>
</property>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="jpaProperties" ref="entityProps" />
</bean>
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="false" />
<property name="database"
value="${jpaVendorAdapter.database}" />
<property name="databasePlatform"
value="${jpaVendorAdapter.databasePlatform}" />
</bean>
<util:properties id="entityProps">
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.jdbc.fetch_size">30</prop>
<prop key="hibernate.jdbc.batch_size">15</prop>
<prop key="hibernate.order_inserts">true</prop>
<prop key="hibernate.order_updates">true</prop>
<prop key="hibernate.check_nullability">false</prop>
<prop key="javax.persistence.sharedCache.mode">ENABLE_SELECTIVE</prop>
<prop key="hibernate.generate_statistics">false</prop>
<prop key="hibernate.id.new_generator_mappings">true</prop>
<prop key="hibernate.id.optimizer.pooled.prefer_lo">true</prop>
<prop key="hibernate.archive.autodetection">class</prop>
<!-- 开启一级缓存 -->
<prop key="hibernate.cache.use_query_cache">true</prop>
<!-- 开启二级缓存 -->
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<!-- 缓存,ehcache实现 -->
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
</prop>
<prop key="net.sf.ehcache.configurationResourceName">cache/ehcache.xml</prop>
</util:properties>
<!-- Spring Data Jpa配置 jpa Dao必须定义该标签 -->
<jpa:repositories
base-package="com.szhis.frsoft.repository"
factory-class="com.szhis.frsoft.common.persistence.FRJpaRepositoryFactoryBean"
transaction-manager-ref="transactionManager"
entity-manager-factory-ref="entityManagerFactory"
repository-impl-postfix="Impl" />
</beans>
config.properties
#jpa配置
jpaVendorAdapter.database = MYSQL
jpaVendorAdapter.databasePlatform = org.hibernate.dialect.MySQL5Dialect
#jdbc配置
jdbc.driverClassName = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://127.0.1:3306/fr-db01?useSSL=false
jdbc.username = root
jdbc.password = 1234
#数据库连接池-c3p0
jdbc.checkoutTimeout = 2000
#初始化时获取三个连接,取值应在minPoolSize与maxPoolSize之间
jdbc.initialPoolSize = 5
jdbc.minPoolSize = 5
jdbc.maxPoolSize = 15
#数据源2
jdbc2.driverClassName = com.mysql.jdbc.Driver
jdbc2.url = jdbc:mysql://127.0.1:3306/fr-db02?useSSL=false
jdbc2.username = root
jdbc2.password = 1234
#数据库连接池-c3p0
jdbc2.checkoutTimeout = 2000
#初始化时获取三个连接,取值应在minPoolSize与maxPoolSize之间
jdbc2.initialPoolSize = 5
jdbc2.minPoolSize = 5
jdbc2.maxPoolSize = 15
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.szhis.frsoft</groupId>
<artifactId>multiple-dataSource-ex1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<!-- Generic properties -->
<java.version>1.7</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- common -->
<commons-lang3.version>3.2.1</commons-lang3.version>
<commons-dbutils.version>1.6</commons-dbutils.version>
<guava.version>16.0.1</guava.version>
<commons-codec.version>1.9</commons-codec.version>
<!-- 数据连接 -->
<mysql.version>5.1.40</mysql.version>
<!-- sql server driver 注意jdk7必须使用1.3.0版本1.3.0以下不支持jdk7 -->
<jtds.version>1.3.0</jtds.version>
<!-- Web -->
<jsp.version>2.2</jsp.version>
<jstl.version>1.2</jstl.version>
<servlet.version>2.5</servlet.version>
<!-- Spring -->
<spring-framework.version>4.1.9.RELEASE</spring-framework.version>
<spring-data-jpa.version>1.7.4.RELEASE</spring-data-jpa.version>
<!-- hibernate -->
<hibernate.version>4.3.11.Final</hibernate.version>
<hibernate-validator.version>5.0.3.Final</hibernate-validator.version>
<jackson-datatype-hibernate4.version>2.9.5</jackson-datatype-hibernate4.version>
<!-- json -->
<jackson.version>2.6.7</jackson.version>
<aspectj.version>1.7.4</aspectj.version>
<shiro.version>1.2.3</shiro.version>
<!-- 缓存 -->
<ehcache-core.version>2.6.8</ehcache-core.version>
<!-- 日志 -->
<logback.version>1.0.13</logback.version>
<slf4j.version>1.7.5</slf4j.version>
<!-- 测试 -->
<junit.version>4.12</junit.version>
<groboutils.version>5</groboutils.version>
<assertj.version>1.5.0</assertj.version>
<mockito.version>1.9.5</mockito.version>
<selenium.version>2.40.0</selenium.version>
</properties>
<dependencies>
<!-- java公共组件 -->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<!-- shiro依赖commons-beanutils包 -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.8.3</version>
</dependency>
<!-- 编码解码工具md5,sha1,base64 -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons-codec.version}</version>
</dependency>
<!-- 文件上传 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!-- 数据库驱动器,mysql driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- 数据库连接池,tomcat-jdbc -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
<version>7.0.54</version>
<scope>provided</scope>
</dependency>
<!-- spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<!-- Spring MVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<!-- spring aop -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
<!-- Other Web dependencies -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>${servlet.version}</version>
<scope>provided</scope>
</dependency>
<!-- websocket -->
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<!-- Spring and Transactions -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<!-- Logging with SLF4J & LogBack -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
<scope>runtime</scope>
</dependency>
<!-- 代码直接调用log4j会被桥接到slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>${slf4j.version}</version>
<scope>runtime</scope>
</dependency>
<!-- 代码直接调用common-logging会被桥接到slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${slf4j.version}</version>
<scope>runtime</scope>
</dependency>
<!-- 代码直接调用java.util.logging会被桥接到slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>${slf4j.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.googlecode.log4jdbc</groupId>
<artifactId>log4jdbc</artifactId>
<version>1.2</version>
<scope>runtime</scope>
</dependency>
<!-- LOGGING end -->
<!-- JSON begin -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate4</artifactId>
<version>${jackson-datatype-hibernate4.version}</version>
<!-- <version>2.4.0</version> -->
</dependency>
<!-- JSON end -->
<!-- Hibernate -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- spring data access -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>${spring-data-jpa.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.3</version>
<exclusions>
<exclusion>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 使用apache httpclient做代理服务DebugProxyController -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
<!-- 测试组件 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring-framework.version}</version>
<scope>test</scope>
</dependency>
<!-- 緩存cache -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.6.8</version>
</dependency>
</dependencies>
</project>
java代码
使用aop注解需要注意:在spring中药支持注解开发,<aop:aspectj-autoproxy proxy-target-class="true" />
package com.szhis.frsoft.common.datasource;
import java.lang.reflect.Method;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* @desc 多数据源,切面处理类
* @author jaden.liu
* @createTime 2018年10月1日 下午7:51:06
* @version v1.0
*/
@Aspect
@Component
@Order(1)
public class DataSourceAspect {
protected Logger logger = LoggerFactory.getLogger(getClass());
@Pointcut("@annotation(com.szhis.frsoft.common.datasource.FRDataSource)")
public void dataSourcePointCut() {
}
@Around("dataSourcePointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
FRDataSource ds = method.getAnnotation(FRDataSource.class);
if (ds == null) {
DynamicDataSource.setDataSource(DataSourceNames.FIRST);
logger.info("set datasource is " + DataSourceNames.FIRST);
} else {
DynamicDataSource.setDataSource(ds.name());
logger.info("set datasource is " + ds.name());
}
try {
return point.proceed();
} finally {
DynamicDataSource.clearDataSource();
logger.info("clean datasource");
}
}
}
package com.szhis.frsoft.common.datasource;
/**
* @desc 增加多数据源,在此配置
* @author jaden.liu
* @createTime 2018年10月1日 下午7:47:49
* @version v1.0
*/
public interface DataSourceNames {
String FIRST = "first";
String SECOND = "second";
}
package com.szhis.frsoft.common.datasource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return getDataSource();
}
/*
*ThreadLocal 用于提供线程局部变量,在多线程环境可以保证各个线程里的变量独立于其它线程里的变量。
* 也就是说 ThreadLocal 可以为每个线程创建一个【单独的变量副本】
* 相当于线程的 private static 类型变量。
*/
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public static void setDataSource(String dataSource) {
contextHolder.set(dataSource);
}
public static String getDataSource() {
return contextHolder.get();
}
public static void clearDataSource() {
contextHolder.remove();
}
}
package com.szhis.frsoft.common.datasource;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @desc 多数据源注解
* @author jaden.liu
* @createTime 2018年10月1日 下午6:25:09
* @version v1.0
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FRDataSource {
/**
* @desc 设置数据源
* @author jaden.liu
* @createTime 2018年10月1日 下午6:25:42
* @return String
*/
String name() default "";
}
在后台就可以使用EntityManager.createQuery()方法了
测试用例就不传了,想要的了解更多可以私聊
就这些东西了,相信剩下的东西可以百度,能看我这个博客的maven要回玩才行啊!