1、采用SpringMVC+mybatis
2、动态切换数据源实现,单独测试有效
public class DataSources extends AbstractRoutingDataSource{
@Override
protected Object determineCurrentLookupKey() {
return DataSourceSwitch.getDataSourceType();
}
}
3、Mybatis不同数据库语言支持实现,单独测试有效
<!--支持多类型数据库配置-->
<bean id="vendorProperties"
class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="properties">
<props>
<prop key="Oracle">oracle</prop>
<prop key="MySQL">mysql</prop>
</props>
</property>
</bean>
<bean id="databaseIdProvider" class="org.apache.ibatis.mapping.VendorDatabaseIdProvider">
<property name="properties" ref="vendorProperties" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dynamicDataSource" />
<property name="databaseIdProvider" ref="databaseIdProvider" />
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
…………
<select id="getTime" resultType="java.lang.String" databaseId="oracle">
select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') from dual
</select>
<select id="getTime" resultType="java.lang.String" databaseId="mysql">
select now()
</select>
4、动态切换数据源之后再访问带有databaseId的dao方法就无效了。
5、看SqlSessionFactoryBean源码,databaseId相关代码如下
if (this.databaseIdProvider != null) {
try {
configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
} catch (SQLException var24) {
throw new NestedIOException("Failed getting a databaseId", var24);
}
}
public String getDatabaseId(DataSource dataSource) {
if (dataSource == null) {
throw new NullPointerException("dataSource cannot be null");
} else {
try {
return this.getDatabaseName(dataSource);
} catch (Exception var3) {
log.error("Could not get a databaseId from dataSource", var3);
return null;
}
}
}
断点跟踪代码,只有启动服务的时候执行一次,切换数据源不执行,跪求求高手告知解决办法。献出全部C币。
http://blog.csdn.net/paditang/article/details/78297702 你看看这篇文章能不能帮到你。
以下是mybatis的配置,其他和hibernate相同
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="parentDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}"/>
<!--initialSize: 初始化连接-->
<property name="initialSize" value="5"/>
<!--maxIdle: 最大空闲连接-->
<property name="maxIdle" value="15"/>
<!--minIdle: 最小空闲连接-->
<property name="minIdle" value="5"/>
<!--maxActive: 最大连接数量-->
<property name="maxActive" value="20"/>
<property name="minEvictableIdleTimeMillis" value="18000000"/>
<!--removeAbandoned: 是否自动回收超时连接-->
<property name="removeAbandoned" value="true"/>
<!--removeAbandonedTimeout: 超时时间(以秒数为单位)-->
<property name="removeAbandonedTimeout" value="180"/>
<!--maxWait: 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒-->
<property name="maxWait" value="3000"/>
<property name="validationQuery">
<value>SELECT 1</value>
</property>
<property name="testOnBorrow">
<value>true</value>
</property>
</bean>
<bean parent="parentDataSource" id="db_record_read">
<property name="url" value="${jdbc.url.read}"/>
<property name="username" value="${jdbc.username.read}"/>
<property name="password" value="${jdbc.password.read}"/>
</bean>
<bean parent="parentDataSource" id="db_record_write">
<property name="url" value="${jdbc.url.write}"/>
<property name="username" value="${jdbc.username.write}"/>
<property name="password" value="${jdbc.password.write}"/>
</bean>
<bean parent="parentDataSource" id="db_vehicle">
<property name="url" value="${jdbc.url.vehicle}"/>
<property name="username" value="${jdbc.username.vehicle}"/>
<property name="password" value="${jdbc.password.vehicle}"/>
</bean>
<bean parent="parentDataSource" id="db_admin">
<property name="url" value="${jdbc.url.admin}"/>
<property name="username" value="${jdbc.username.admin}"/>
<property name="password" value="${jdbc.password.admin}"/>
</bean>
<bean class="com.xx.config.datasource.DynamicDataSource" id="dataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry value-ref="db_record_read" key="db_record_read"></entry>
<entry value-ref="db_record_write" key="db_record_write"></entry>
<entry value-ref="db_vehicle" key="db_vehicle"></entry>
<entry value-ref="db_admin" key="db_admin"></entry>
</map>
</property>
<property name="defaultTargetDataSource" ref="db_record_read"></property>
</bean>
<!-- 获取MyBatis sqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
p:dataSource-ref="dataSource"
p:configLocation="classpath:myBatisConf.xml"
p:mapperLocations="classpath:com/xx/mapping/*.xml"><!-- 扫描Mapper文件 -->
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<!--使用下面的方式配置参数,一行配置一个 -->
<value>
helperDialect=MySql
</value>
</property>
</bean>
</array>
</property>
</bean>
<!-- 扫描直接使用mapper接口类操作dao -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"
p:basePackage="com.xx.mapping">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置基于注解的声明式事务 -->
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
问题已经初步解决了。
原因是因为mybatis的SqlSessionFactoryBean只在spring配置文件第一次加载的时候初始化,动态切换数据源之后并没有通知SqlSessionFactoryBean
修改databaseId为当前数据源,所以依旧使用默认数据源执行sql。
解决办法:
1、跟踪源码发现SqlSessionFactoryBean提供了修改databaseId的方法,如下
if (this.databaseIdProvider != null) {
try {
**configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));**
} catch (SQLException var24) {
throw new NestedIOException("Failed getting a databaseId", var24);
}
}
configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));//修改databaseId
2、通过sqlSessionFactoryBean.getObject().getConfiguration()可获取到configuration对象。
3、sqlSessionFactoryBean是Spring初始化的bean。
4、切换数据源之后调用修改databaseId即可。
配置了几个SqlSessionFactory实例呢? 一个的话,你这样修改了Configuration对象的的databaseId的话,对使用其他数据源的代码没有影响吗?