SpringMvc项目配置多数据源
1. 首选添加另外的数据源
数据源配置在dbconfig.properties文件
1 | #db1 |
2.在springmvc配置文件中增加对第二个数据源的支持
1 | <!-- 阿里 druid数据库连接池 --> |
这时候项目已经有两个数据源了。但是什么时候选择哪个数据源,我们还要告诉程序,告诉指定哪一个数据源。需要继承spring给我们提供的AbstractRoutingDataSource类。在我们需要动态切换另外的数据源时,可以提供设置指定数据源。但需要确保不同线程中的数据源不互相干扰。这时可以利用ThreadLocal在同一个线程中传递上下文信息,达到多数据源访问的效果。1
2
3
4
5
6
7//MultiDataSource.java
public class MultiDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DatabaseContentHolder.getDataSource();
}
}
定义枚举类来枚举数据源1
2
3
4public enum DBSource {
DB1(),
DB2()
}
1 | public class DatabaseContentHolder { |
在spring 配置文件中注册数据源.map内的key需要跟数据源枚举类中定义的值相同,value-ref的值需要跟spring配置中定义的数据源的id相同。1
2
3
4
5
6
7
8
9
10
11<!--多数据源配置-->
<bean id="multiDataSource" class="com.***.MultiDataSource">
<property name="targetDataSources">
<map key-type="com.***.DBSource">
<entry value-ref="db1" key="DB1"/>
<entry value-ref="db2" key="DB2"/>
</map>
</property>
<property name="defaultTargetDataSource" ref="dataSource">
</property>
</bean>
注册好数据源,还要把数据源绑定到mybaits和事务中。1
2
3
4
5
6
7
8
9
10
11<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="multiDataSource"></property>
</bean>
<!-- 配置mybatis -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="multiDataSource"/>
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"></property>
<!-- mapper扫描 -->
<property name="mapperLocations" value="classpath:mybatis/*/*.xml"></property>
</bean>
这样多数据源就配置完成了。如果不指定数据源,默认使用db1的数据源,如果需要动态切换到db2,则需要手动调用DatabaseContentHolder.setDataSource(DBSource.DB2)来告知这个线程都采用db2的数据源。
3.利用aop和注解实现自动指定。
先定义一个方法注解1
2
3
4
5
6
7//Database.java
@Documented
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Database {
DBSource source() default DBSource.READ_WRITE;
}
然后利用aop,在加入该注解的方法前调用DatabaseContentHolder.setDataSource(DBSource.DB2)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24@Aspect
@Component
public class DatabaseAspect {
@Pointcut("@annotation(com.***.Database)")
public void aspect() {
}
@Before("aspect()")
public void doBefore(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method.isAnnotationPresent(Database.class)) {
Database database = method.getAnnotation(Database.class);
DatabaseContentHolder.setDataSource(database.source());
}
}
@AfterReturning(pointcut = "aspect()")
public void doAfter(JoinPoint joinPoint) {
DatabaseContentHolder.remove();
}
}
这样,如果方法没有Database注解,就默认调用db1连接,如果添加了@Database(source = DBSource.ONLY_READ)注解则调用db2