一、背景
最近几天在忙集团演示的项目,现有的框架是 sql server、oracle、mysql 均支持的,由于此项目用的是 mysql 数据库,而它还需要用到集团门禁系统的访客信息表和发卡系统的车辆信息表,而这两套系统用到的是 sql server 数据库。
故需要在一个系统中连接两个不同的数据库(一个 mysql,一个 sql server,且 mysql 连接两个库),即配置两个数据源且连接 3 个数据库。
二、实现步骤
2.1 编写配置文件
编写两个数据库配置文件,用于配置数据库用户名、密码等相关信息,由于使用的是 maven 工程,相关的目录结构如下
2.2 配置 mysql 的数据库
1、先配置 mysql 的连接信息
2、配置 sql server 的数据库相关信息,由于 sql server 连接了两个数据库,所以在一个配置文件里面配置了两个数据库名字和密码
2.3 编写配置文件
编写两套 spring 配置文件,一套连接 mysql,一套连接 sql server。
首先编写 spring 和 mysql 连接的配置文件 spring-mybatis.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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.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.1.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">
<!-- 自动扫描 -->
<context:component-scan base-package="com.zit">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
</context:component-scan>
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:mssql.properties</value>
<value>classpath:mysql.properties</value>
</list>
</property>
<property name="ignoreUnresolvablePlaceholders" value="false"></property>
</bean>
<!-- 配置数据库连接 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="driverClassName" value="${driver}" />
<property name="url" value="${url}${dbName}${encoding}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
<!-- 初始化连接大小 -->
<property name="initialSize" value="${initialSize}"></property>
<!-- 连接池最大数量 -->
<property name="maxActive" value="${maxActive}"></property>
<!-- 连接池最小空闲 -->
<property name="minIdle" value="${minIdle}"></property>
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="${maxWait}"></property>
<!-- 解决长时间不连接,连接失败问题 -->
<property name="testOnBorrow" value="${testOnBorrow}"></property>
<property name="testOnReturn" value="${testOnReturn}"></property>
<property name="testWhileIdle" value="${testWhileIdle}"></property>
<property name="validationQuery" value="${validationQuery}"></property>
<!-- 打开removeAbandoned功能 -->
<property name="removeAbandoned" value="${removeAbandoned}" />
<!-- 1800秒,也就是30分钟 -->
<property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}" />
<!-- 关闭abanded连接时输出错误日志 -->
<property name="logAbandoned" value="${logAbandoned}" />
<!-- 监控数据库 -->
<property name="proxyFilters">
<list>
<ref bean="statfilter" />
<ref bean="logFilter" />
</list>
</property>
<property name="filters" value="${filters}" />
</bean>
<bean id="statfilter" class="com.alibaba.druid.filter.stat.StatFilter">
<!-- 开启合并sql -->
<property name="mergeSql" value="true" />
<!-- 开启慢查询语句,1秒 -->
<property name="slowSqlMillis" value="1000" />
<property name="logSlowSql" value="true" />
</bean>
<bean id="logFilter" class="com.alibaba.druid.filter.logging.Log4jFilter">
<!-- <property name="resultSetLogEnabled" value="false" /> -->
<!-- <property name="statementExecutableSqlLogEnable" value="true" /> -->
</bean>
<!-- 配置druid监控spring jdbc -->
<bean id="druid-stat-interceptor"
class="com.alibaba.druid.support.spring.stat.DruidStatInterceptor">
</bean>
<bean id="druid-stat-pointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut"
scope="prototype">
<property name="patterns">
<list>
<value>com.zit.cac.service.*</value>
</list>
</property>
</bean>
<aop:config>
<aop:pointcut id="cacpc" expression="execution(public * com.zit.cac.service.*.*(..))" />
<aop:advisor advice-ref="cacTxAdvice" pointcut-ref="cacpc" />
<aop:advisor advice-ref="druid-stat-interceptor" pointcut-ref="druid-stat-pointcut" />
</aop:config>
<tx:advice id="cacTxAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="append*" propagation="REQUIRED" />
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="modify*" propagation="REQUIRED" />
<tx:method name="edit*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="remove*" propagation="REQUIRED" />
<tx:method name="repair" propagation="REQUIRED" />
<tx:method name="delAndRepair" propagation="REQUIRED" />
<tx:method name="get*" propagation="REQUIRED" />
<tx:method name="datagrid*" propagation="REQUIRED" />
<tx:method name="query*" propagation="SUPPORTS" read-only="true" />
<tx:method name="select*" propagation="SUPPORTS" read-only="true" />
<tx:method name="find*" propagation="SUPPORTS" read-only="true" />
<tx:method name="load*" propagation="SUPPORTS" read-only="true" />
<tx:method name="search*" propagation="SUPPORTS" read-only="true" />
<tx:method name="count*" propagation="SUPPORTS" read-only="true" />
<tx:method name="truncate*" propagation="SUPPORTS" read-only="true" />
<tx:method name="menu*" propagation="SUPPORTS" read-only="true" />
<tx:method name="exist*" propagation="SUPPORTS" read-only="true" />
</tx:attributes>
</tx:advice>
<!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 自动扫描mapping.xml文件 -->
<property name="mapperLocations" value="classpath:com/zit/**/mapping/*.xml"></property>
<!-- mybatis配置文件 -->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
</bean>
<!-- DAO接口所在包名,Spring会自动查找其下的类 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.zit.zVision.vehiclePassRecord.dao,com.zit.zVision.fvms.dao,com.zit.cac.dao,com.zit.zVision.trajectory.dao"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
</beans>
其次,编写 spring 连接 sql server 数据库的配置文件 spring-mybatis-mssql.xml,需要注意的是,在这个配置文件里面配置了两套数据源 dataSourceIacs和dataSourceTis,且需要在运行的时候才指定到底使用哪个数据库。
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.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.1.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">
<!-- 自动扫描 -->
<context:component-scan base-package="com.zit">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
</context:component-scan>
<!-- 配置数据库连接 -->
<bean id="dataSourceTis" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="driverClassName" value="${mssqldriver}" />
<property name="url" value="${tisurl}${tisdbName}" />
<property name="username" value="${tisusername}" />
<property name="password" value="${tispassword}" />
<!-- 初始化连接大小 -->
<property name="initialSize" value="${initialSize}"></property>
<!-- 连接池最大数量 -->
<property name="maxActive" value="${maxActive}"></property>
<!-- 连接池最小空闲 -->
<property name="minIdle" value="${minIdle}"></property>
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="${maxWait}"></property>
<!-- 解决长时间不连接,连接失败问题 -->
<property name="testOnBorrow" value="${testOnBorrow}"></property>
<property name="testOnReturn" value="${testOnReturn}"></property>
<property name="testWhileIdle" value="${testWhileIdle}"></property>
<property name="validationQuery" value="${mssqlvalidationQuery}"></property>
<!-- 打开removeAbandoned功能 -->
<property name="removeAbandoned" value="${removeAbandoned}" />
<!-- 1800秒,也就是30分钟 -->
<property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}" />
<!-- 关闭abanded连接时输出错误日志 -->
<property name="logAbandoned" value="${logAbandoned}" />
<!-- 监控数据库 -->
<property name="proxyFilters">
<list>
<ref bean="statfilterMssql" />
<ref bean="logFilterMssql" />
</list>
</property>
<property name="filters" value="${filters}" />
</bean>
<bean id="dataSourceIacs" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="driverClassName" value="${mssqldriver}" />
<property name="url" value="${iacsurl}${iacsdbName}" />
<property name="username" value="${iacsusername}" />
<property name="password" value="${iacspassword}" />
<!-- 初始化连接大小 -->
<property name="initialSize" value="${initialSize}"></property>
<!-- 连接池最大数量 -->
<property name="maxActive" value="${maxActive}"></property>
<!-- 连接池最小空闲 -->
<property name="minIdle" value="${minIdle}"></property>
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="${maxWait}"></property>
<!-- 解决长时间不连接,连接失败问题 -->
<property name="testOnBorrow" value="${testOnBorrow}"></property>
<property name="testOnReturn" value="${testOnReturn}"></property>
<property name="testWhileIdle" value="${testWhileIdle}"></property>
<property name="validationQuery" value="${mssqlvalidationQuery}"></property>
<!-- 打开removeAbandoned功能 -->
<property name="removeAbandoned" value="${removeAbandoned}" />
<!-- 1800秒,也就是30分钟 -->
<property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}" />
<!-- 关闭abanded连接时输出错误日志 -->
<property name="logAbandoned" value="${logAbandoned}" />
<!-- 监控数据库 -->
<property name="proxyFilters">
<list>
<ref bean="statfilterMssql" />
<ref bean="logFilterMssql" />
</list>
</property>
<property name="filters" value="${filters}" />
</bean>
<!-- 下面的是切换数据库的自定义类 -->
<bean id="multipleDataSource" class="com.zit.zVision.vimm.util.MultipleDataSource">
<!--默认的数据源-->
<property name="defaultTargetDataSource" ref="dataSourceTis"></property>
<property name="targetDataSources">
<map>
<entry key="dataSourceTis" value-ref="dataSourceTis"></entry>
<entry key="dataSourceIacs" value-ref="dataSourceIacs"></entry>
</map>
</property>
</bean>
<!-- 慢SQL记录 *start*-->
<bean id="statfilterMssql" class="com.alibaba.druid.filter.stat.StatFilter">
<property name="mergeSql" value="true" />
<property name="slowSqlMillis" value="1000" />
<property name="logSlowSql" value="true" />
</bean>
<bean id="logFilterMssql" class="com.alibaba.druid.filter.logging.Log4jFilter">
<!-- <property name="resultSetLogEnabled" value="false" /> -->
<!-- <property name="statementExecutableSqlLogEnable" value="true" /> -->
</bean>
<!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
<bean id="transactionManagerMssql" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="multipleDataSource" />
</bean>
<!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
<bean id="sqlSessionFactoryMssql" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="multipleDataSource" />
<!-- 自动扫描mapping.xml文件 -->
<property name="mapperLocations" value="classpath:com/zit/**/vimm/**/mapping/*.xml"></property>
<!-- mybatis配置文件 -->
<property name="configLocation" value="classpath:mybatis-config-mssql.xml"></property>
</bean>
<!-- DAO接口所在包名,Spring会自动查找其下的类 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.zit.zVision.vimm.tis.dao,com.zit.zVision.vimm.iacs.dao"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryMssql"></property>
</bean>
</beans>
其中,在这个配置文件中,配置了一个切换数据库的自定义类 MultipleDataSource
public class MultipleDataSource extends AbstractRoutingDataSource{
private static final ThreadLocal<String> dataSourceKey = new InheritableThreadLocal<String>();
public static void setDataSourceKey(String dataSource){
dataSourceKey.set(dataSource);
}
@Override
protected Object determineCurrentLookupKey() {
return dataSourceKey.get();
}
}
2.4 编写 mybatis 配置文件
编写两套 mybatis 的配置文件,由于我的分页查询使用的是 PageHelper,所以需要在配置文件里面配置相应的标签
1、首先编写 mysql 的 mybatis 配置文件 mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="callSettersOnNulls" value="true"/>
<setting name="logImpl" value="LOG4J" />
</settings>
<!-- 别名 -->
<typeAliases>
<package name="com.zit.cac.entity"/>
</typeAliases>
<!-- MyBatis实现分页插件 -->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!-- 其中sqlserver对应2005、2008-->
<property name="helperDialect" value="mysql"/>
<property name="offsetAsPageNum" value="false"/>
<property name="rowBoundsWithCount" value="false"/>
<property name="pageSizeZero" value="true"/>
<property name="reasonable" value="true"/>
<property name="supportMethodsArguments" value="false"/>
<property name="returnPageInfo" value="none"/>
</plugin>
</plugins>
</configuration>
然后编写 sql server 的 mybatis 配置文件 mybatis-config-mssql.xml,一开始配置的只有一个配置文件,发现调用后台的数据库时一直报错,花了上午半天的时间,才发现他们的 helperDialect 不同的数据库需要不同的配置,所以这点要注意一下。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="callSettersOnNulls" value="true"/>
<setting name="logImpl" value="LOG4J" />
</settings>
<!-- MyBatis实现分页插件 -->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!-- 其中sqlserver对应2005、2008-->
<property name="helperDialect" value="sqlserver"/>
<property name="offsetAsPageNum" value="false"/>
<property name="rowBoundsWithCount" value="false"/>
<property name="pageSizeZero" value="true"/>
<property name="reasonable" value="true"/>
<property name="supportMethodsArguments" value="false"/>
<property name="returnPageInfo" value="none"/>
</plugin>
</plugins>
</configuration>
2.5 修改 web.xml
在 web.xml 中配置相应标签,加载 spring 的配置文件
2.6 设定数据源
在 service 层设定数据源,查询数据,如下: