您的位置:首页 > 编程语言 > Java开发

spring+mybaties 配置多数据源

2016-02-25 17:47 441 查看
在实际的开发中遇到了需要2个数据源的情况。这里我们就需要配置多数据源了。
1  首先配置多数据源有2种实现方式   
1)简单方式:一般情况下,我们可以配置多个数据源,然后为每个数据源写一套对应的sessionFactory和dao层代码我们称之为静态数据源配置
2)动态方式: 配置多个数据源,只对应一套sessionFactory,数据源之间可以动态切换。</span>
2   這两种方式相比较来看,第一种如果以后要配置多个数据源的话,对应都要配置sessionfactory. 第2种只需配置多个数据源自由切换对应一个sessionfactory 明显比第一个更装B一点。下面就是详细介绍我自己配置的第2中方法。首先是先配置2个数据源


<pre name="code" class="html"><beans xmlns="http://www.springframework.org/schema/beans"


xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd ">

<description>公共的默认数据源配置</description>

<!-- portal master数据库 -->
<bean id="dataSource_master" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="${db.master.dbUrl}" />
<property name="username" value="${db.master.userName}" />
<property name="password" value="${db.master.passWord}" />
<!-- 连接池启动时创建的初始化连接数量(默认值为0) -->
<property name="initialSize" value="1"/>
<!-- 连接池中可同时连接的最大的连接数 默认 8-->
<property name="maxActive" value="100"/>
<!-- 连接池中最小的空闲的连接数,低于这个数量会被创建新的连接 -->
<property name="minIdle" value="5"/>
<!-- 连接池中最大的空闲的连接数,超过的空闲连接将被释放,如果设置为负数表示不限制 默认8 -->
<property name="maxIdle" value="30"/>
<!-- 最大等待时间,当没有可用连接时,连接池等待连接释放的最大时间,超过该时间限制会抛出异常,如果设置-1表示无限等待 -->
<property name="maxWait" value="60000"/>
<!-- 超过removeAbandonedTimeout时间后,是否进 行没用连接(废弃)的回收(默认为false,调整为true)-->
<property name="removeAbandoned" value="true"/>
<!-- 超过时间限制,回收没有用(废弃)的连接(默认为 300秒,调整为180) -->
<property name="removeAbandonedTimeout" value="180"/>
<!-- 默认提交 -->
<property name="defaultAutoCommit" value="true"/>
<!-- 打开检查,用异步线程evict进行检查 -->
<property name="testWhileIdle" value="true"/>
<!-- 就是在进行borrowObject进行处理时,对拿到的connection进行validateObject校验 -->
<property name="testOnBorrow" value="false"/>
<!-- 就是在进行returnObject对返回的connection进行validateObject校验,个人觉得对数据库连接池的管理意义不大 -->
<property name="testOnReturn" value="false"/>
<!--  代表检查的sql -->
<property name="validationQuery" value="select 1 from dual"/>
<!-- 代表在执行检查时,通过statement设置,statement.setQueryTimeout(validationQueryTimeout)  -->
<property name="validationQueryTimeout" value="1"/>
<property name="timeBetweenEvictionRunsMillis" value="30000"/>
<!-- 代表每次检查链接的数量,建议设置和maxActive一样大,这样每次可以有效检查所有的链接.  -->
<property name="numTestsPerEvictionRun" value="100"/>
</bean>

<!-- portal master数据库 -->
<bean id="dataSource_website" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="${db.website.dbUrl}" />
<property name="username" value="${db.website.userName}" />
<property name="password" value="${db.website.passWord}" />
<!-- 连接池启动时创建的初始化连接数量(默认值为0) -->
<property name="initialSize" value="1"/>
<!-- 连接池中可同时连接的最大的连接数 默认 8-->
<property name="maxActive" value="100"/>
<!-- 连接池中最小的空闲的连接数,低于这个数量会被创建新的连接 -->
<property name="minIdle" value="5"/>
<!-- 连接池中最大的空闲的连接数,超过的空闲连接将被释放,如果设置为负数表示不限制 默认8 -->
<property name="maxIdle" value="30"/>
<!-- 最大等待时间,当没有可用连接时,连接池等待连接释放的最大时间,超过该时间限制会抛出异常,如果设置-1表示无限等待 -->
<property name="maxWait" value="60000"/>
<!-- 超过removeAbandonedTimeout时间后,是否进 行没用连接(废弃)的回收(默认为false,调整为true)-->
<property name="removeAbandoned" value="true"/>
<!-- 超过时间限制,回收没有用(废弃)的连接(默认为 300秒,调整为180) -->
<property name="removeAbandonedTimeout" value="180"/>
<!-- 默认提交 -->
<property name="defaultAutoCommit" value="true"/>
<!-- 打开检查,用异步线程evict进行检查 -->
<property name="testWhileIdle" value="true"/>
<!-- 就是在进行borrowObject进行处理时,对拿到的connection进行validateObject校验 -->
<property name="testOnBorrow" value="false"/>
<!-- 就是在进行returnObject对返回的connection进行validateObject校验,个人觉得对数据库连接池的管理意义不大 -->
<property name="testOnReturn" value="false"/>
<!--  代表检查的sql -->
<property name="validationQuery" value="select 1 from dual"/>
<!-- 代表在执行检查时,通过statement设置,statement.setQueryTimeout(validationQueryTimeout)  -->
<property name="validationQueryTimeout" value="1"/>
<property name="timeBetweenEvictionRunsMillis" value="30000"/>
<!-- 代表每次检查链接的数量,建议设置和maxActive一样大,这样每次可以有效检查所有的链接.  -->
<property name="numTestsPerEvictionRun" value="100"/>
</bean>


4 然后是配置转换器

<bean id="data_dataSource" class="com.shangde.common.datesource.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="dataSource_website" value-ref="dataSource_website" />
<entry key="dataSource_master" value-ref="dataSource_master" />
</map>
</property>
<property name="defaultTargetDataSource" ref="dataSource_master" />
</bean>


5配置切面

<!-- 动态数据源切换aop 先于事务的aop  -->
<bean id="dataSourceInterceptor" class="com.shangde.common.datesource.DataSourceInterceptor" />
<aop:config>
<aop:aspect id="dataSourceAspect" ref="dataSourceInterceptor">
<aop:pointcut id="dsMaster" expression="execution(* com.shangde.master.mobile.*.service..*.*(..))" />
<aop:pointcut id="dsWebsite" expression="execution(* com.shangde.master.website.*.service..*.*(..))" />
<aop:before method="setdataSourceMaster" pointcut-ref="dsMaster"/>
<aop:before method="setdataSourceWebsite" pointcut-ref="dsWebsite"/>
</aop:aspect>
</aop:config>
6.配置sessionfactory

<bean id="sqlSessionFactory_master" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="data_dataSource" />
<!-- 全局sqlMapConfig.xml公共配置文件路径 -->
<property name="configLocation" value="classpath:/mybatis_master.xml" />
<property name="typeAliasesPackage" value="com.shangde.master.dmo.*" />
</bean>


7 AbstractRoutingDataSource转换器代码

DynamicDataSource

package com.shangde.common.datesource;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return CustomerContextHolder.getCustomerType();
}
}


DataSourceInterceptor

package com.shangde.common.datesource;

import org.aspectj.lang.JoinPoint;
public class DataSourceInterceptor {

public void setdataSourceMaster(JoinPoint jp) {
CustomerContextHolder.setCustomerType("dataSource_master");
}

public void setdataSourceWebsite(JoinPoint jp) {
CustomerContextHolder.setCustomerType("dataSource_website");
}
}


CustomerContextHolder
package com.shangde.common.datesource;

public class CustomerContextHolder {
public static final String DATA_SOURCE_MASTER = "dataSource_master";
public static final String DATA_SOURCE_WEBSITE = "dataSource_website";
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();
}
}


8 好了代码就这么多了 一些失误的配置自行解决。

原理: AbstractRoutingDataSource
能够通过key的值在 map中寻找对应的 值,也就是对应的数据源。然而怎么才能获得key的值呢?。我们对不同数据源分包(package)管理,同一包下的代码使用了同一数据源。通过AOP来实现,大家都知道web开发常见是三层结构:controller、service、dao。假设我们创建了2个包
package1 ,package2分别对应不同的数据源db1 和db2。在对应的包下面创建 我们 service 包 和 dao 包 ,我们只需要用AOP切
不同数据源下的包名的service的目录即可,当controller层调用service 类时,发现它在 package1 .service
包下,这是spring 切面就会调用 切面类,设置代表数据源的字符串db1然后AbstractRoutingDataSource根据db1這个key在map中找到对应的数据源 db1 .然后我们只是找到了這个数据源,那么怎么用呢。

我们发现AbstractRoutingDataSource
extends AbstractDataSource 发现他继承自 AbstractDataSource。而且刚才我们已经找到了我们到底要那个数据源,这样我们就可以直接使用
這个实现了 AbstractRoutingDataSource 的类作为数据源了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: