這裏主要介紹兩種多數據源方式,一種是SpringMVC+MYbatis註解的方式,一種spring JNDI方式;
總體大概流程:1. 拷貝所需jar
2.寫一個數據庫切換的工具類:DataSourceContextHolder,用來切換數據庫
3.寫一個DynamicDataSource類來繼承AbstractRoutingDataSource,並重寫determineCurrentLookupKey()方法,來達到動態切換數據庫
4. 創建springmvc-servlet.xml文件,然後創建spring配置文件(beans.xml)
5. 在beans.xml文件中配置數據源。我這裏配置的三個數據源
6. 在beans.xml文件中創建sqlSessionFactory實例
7. 在beans.xml文件中配置事物、事物的傳播性
8. 在beans.xml文件中配置AOP
9. 創建一個User對象,配置User.xml文件。寫一個UserMapper接口,用來操作User對象的接口
10. 將User類的路徑以及User.xml文件的路徑在mybatis-config.xml文件中配置
11. 寫一個UserService接口(接口裏面的方法和UserMapper接口裏面的方法一致,返回值和參數可不同,方法名最好一致),並寫UserServiceImpl來實現UserService接口
12.寫Controller類,並在其中寫相對應的方法,給外部調用
mapper:.....存放XXMapper以及實體類的對應表的關係的xml文件
下面一步步的來講解:
1、拷貝jar文件。需要的jar文件入下圖所示,因爲我的項目中用到了json解析,所以導入了json相關的包
2.寫一個數據庫切換的工具類:DataSourceContextHolder,用來切換數據庫
- public class DataSourceContextHolder {
- private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
- public static void setDbType(String dbType) {
- contextHolder.set(dbType);
- }
- public static String getDbType() {
- return ((String) contextHolder.get());
- }
- public static void clearDbType() {
- contextHolder.remove();
- }
- }
3.寫一個DynamicDataSource類來繼承AbstractRoutingDataSource,並重寫determineCurrentLookupKey()方法,來達到動態切換數據庫
- import java.sql.SQLFeatureNotSupportedException;
- import java.util.logging.Logger;
- import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
- public class DynamicDataSource extends AbstractRoutingDataSource {
- @Override
- public Logger getParentLogger() throws SQLFeatureNotSupportedException {
- return null;
- }
- @Override
- protected Object determineCurrentLookupKey() {
- return DataSourceContextHolder. getDbType();
- }
- }
4. 創建springmvc-servlet.xml文件,然後創建spring配置文件(beans.xml),看一下我的springmvc-servlet.xml文件。
這裏配置了一個註解掃描器,一般填自己的主包名就可以了,他會自動掃描我的com.baimi.routerweb包下面所有的帶註解的類或者方法,常變量等。
還配置了一個視圖解析器(如果需要用到jsp文件,就需要配置此解析器)
最後引入我的spring的配置文件:beans.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:context= "http://www.springframework.org/schema/context"
- xmlns:mvc= "http://www.springframework.org/schema/mvc"
- xsi:schemaLocation= "http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
- http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
- <!-- 註解掃描器 -->
- <context:component-scan base-package ="com.baimi.routerweb"/>
- <!-- 配置試圖解析器 -->
- <bean class= "org.springframework.web.servlet.view.InternalResourceViewResolver" >
- <property name ="prefix" value="/"></ property>
- <property name ="suffix" value=".jsp"></ property>
- </bean >
- <import resource ="classpath:beans.xml"/>
- </beans>
5. 在beans.xml文件中配置數據源。我這裏配置的三個數據源,不過在配置數據源之前,先配置一下註解掃描器。然後我接着配置了三個數據源,然後配置動態數據源
- <context:component-scan base-package ="com" />
- <!-- 多數據源配置 -->
- <bean id ="ds_admin" class= "org.apache.commons.dbcp.BasicDataSource" >
- <property name ="driverClassName" value= "com.mysql.jdbc.Driver"></property >
- <property name ="url" value= "jdbc:mysql://192.168.19.72:3307/100msh_admin" ></property >
- <property name ="username" value="root"></ property>
- <property name ="password" value="root"></ property>
- </bean >
- <bean id ="ds_partner" class= "org.apache.commons.dbcp.BasicDataSource" >
- <property name ="driverClassName" value= "com.mysql.jdbc.Driver"></property >
- <property name ="url"
- value= "jdbc:mysql://192.168.19.72:3308/100msh_partner" ></property >
- <property name ="username" value="root"></ property>
- <property name ="password" value="root"></ property>
- </bean >
- <bean id ="ds_mop" class="org.apache.commons.dbcp.BasicDataSource">
- <property name ="driverClassName" value= "com.mysql.jdbc.Driver"></property >
- <property name ="url" value= "jdbc:mysql://192.168.19.72:3309/100msh_mop" ></property >
- <property name ="username" value="root"></ property>
- <property name ="password" value="root"></ property>
- </bean >
- <!-- 動態配置數據源 -->
- <bean id ="dataSource" class= "com.baimi.routerweb.datasource.DynamicDataSource" >
- <property name ="targetDataSources">
- <map key-type ="java.lang.String">
- <entry value-ref ="ds_admin" key= "ds_admin"></entry >
- <entry value-ref ="ds_partner" key= "ds_partner"></entry >
- <entry value-ref ="ds_mop" key="ds_mop"></ entry>
- </map >
- </property >
- <property name ="defaultTargetDataSource" ref= "ds_mop"></property > <!-- 默認使用ds1的數據源 -->
- </bean >
6. 在beans.xml文件中創建sqlSessionFactory實例
- <!-- 創建SqlSessionFactory -->
- <bean id ="sqlSessionFactoryBean" class= "org.mybatis.spring.SqlSessionFactoryBean" >
- <!-- 指定數據源 -->
- <property name ="dataSource" ref="dataSource" />
- <!-- 指定mybatis 的配置文件 -->
- <property name ="configLocation" value= "classpath:mybatis-config.xml" />
- </bean >
7. 在beans.xml文件中配置事物、事物的傳播性
- <!-- 配置事務 -->
- <bean id ="transactionManager"
- class= "org.springframework.jdbc.datasource.DataSourceTransactionManager" >
- <property name ="dataSource" ref="dataSource"></ property>
- </bean >
- <!-- 映射接口 -->
- <bean class ="org.mybatis.spring.mapper.MapperScannerConfigurer">
- <property name ="basePackage" value= "com.baimi.routerweb.mapper"></property >
- </bean >
- <!-- 配置事務的傳播特性 -->
- <tx:advice id ="txAdvice" transaction-manager="transactionManager">
- <tx:attributes >
- <tx:method name ="find*" read-only="true" />
- <tx:method name ="get*" read-only="true" />
- <tx:method name ="query*" read-only="true" />
- <tx:method name ="add*" propagation="REQUIRED" />
- <tx:method name ="update*" propagation="REQUIRED" />
- <tx:method name ="del*" propagation="REQUIRED" />
- </tx:attributes >
- </tx:advice >
8. 在beans.xml文件中配置AOP,注意這裏,expression 後面一定要是自己程序所在包名,複製的時候一定要改掉
- <!-- 配置AOP -->
- <aop:config >
- <!-- 切點 -->
- <aop:pointcut expression ="execution(* com.baimi.routerweb.service..*.*(..))"
- id= "pointcut" />
- <aop:advisor advice-ref ="txAdvice" pointcut-ref="pointcut" />
- </aop:config >
9. 創建一個User對象,配置User.xml文件。寫一個UserMapper接口,用來操作User對象的接口。
User類屬性有點長,請忽略這些屬性
- public class User {
- private int userId;
- private int compId;
- private String euserName;
- private String euserPhone;
- private int euserStatus;
- private String eAddTime;
- private String eLeaveTime;
- private String eUserNameCn;
- private int cUserId;
- private String scDown;
- private String userDesc;
- public int getUserId() {
- return userId;
- }
- public void setUserId( int userId) {
- this. userId = userId;
- }
- public int getCompId() {
- return compId;
- }
- public void setCompId( int compId) {
- this. compId = compId;
- }
- public String getEuserName() {
- return euserName;
- }
- public void setEuserName(String euserName) {
- this. euserName = euserName;
- }
- public String getEuserPhone() {
- return euserPhone;
- }
- public void setEuserPhone(String euserPhone) {
- this. euserPhone = euserPhone;
- }
- public int getEuserStatus() {
- return euserStatus;
- }
- public void setEuserStatus( int euserStatus) {
- this. euserStatus = euserStatus;
- }
- public String geteAddTime() {
- return eAddTime;
- }
- public void seteAddTime(String eAddTime) {
- this. eAddTime = eAddTime;
- }
- public String geteLeaveTime() {
- return eLeaveTime;
- }
- public void seteLeaveTime(String eLeaveTime) {
- this. eLeaveTime = eLeaveTime;
- }
- public String geteUserNameCn() {
- return eUserNameCn;
- }
- public void seteUserNameCn(String eUserNameCn) {
- this. eUserNameCn = eUserNameCn;
- }
- public int getcUserId() {
- return cUserId;
- }
- public void setcUserId( int cUserId) {
- this. cUserId = cUserId;
- }
- public String getScDown() {
- return scDown;
- }
- public void setScDown(String scDown) {
- this. scDown = scDown;
- }
- public String getUserDesc() {
- return userDesc;
- }
- public void setUserDesc(String userDesc) {
- this. userDesc = userDesc;
- }
- }
- public interface UserMapper {
- public User getUser(String euserPhone);
- }
編寫User.xml文件,該文件裏面配置User類裏面的屬性和表中的那些字段進行對應,以及在UserMapper中定義的查詢的方法,在User.xml中寫上對應的查詢語句,我這裏是查的t_expand_user 表
- <?xml version="1.0" encoding= "UTF-8" ?>
- <!DOCTYPE mapper
- PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
- "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
- <mapper namespace= "com.baimi.routerweb.mapper.UserMapper" >
- <resultMap type ="User" id="usermap">
- <result property ="userId" column="euser_id" />
- <result property ="compId" column="comp_id" />
- <result property ="euserName" column="euser_name" />
- <result property ="euserPhone" column="euser_phone" />
- <result property ="euserStatus" column="euser_status" />
- <result property ="eAddTime" column="e_add_time" />
- <result property ="eLeaveTime" column="e_leave_time" />
- <result property ="eUserNameCn" column="euser_name_cn" />
- <result property ="cUserId" column="user_id" />
- <result property ="scDown" column="sc_own" />
- <result property ="userDesc" column="euser_desc" />
- </resultMap >
- <!-- 查詢一條記錄 -->
- <select id ="getUser" parameterType="java.lang.String" resultMap= "usermap">
- select * from t_expand_user where euser_phone=#{euserPhone}
- </select >
- </mapper>
10. 將User類的路徑以及User.xml文件的路徑在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>
- <!-- 別名 -->
- <typeAliases >
- <typeAlias type ="com.baimi.routerweb.entity.User" alias= "User" />
- </typeAliases >
- <mappers >
- <mapper resource ="com/baimi/routerweb/mapper/User.xml" />
- </mappers >
- </configuration>
11. 寫一個UserService接口(接口裏面的方法和UserMapper接口裏面的方法一致,返回值和參數可不同,方法名最好一致),並寫UserServiceImpl來實現UserService接口
- public interface UserService {
- public User getUser(String euserPhone);
- }
UserServiceImpl裏面要做的就是調用UserMapper中的方法
- import javax.annotation.Resource;
- import org.springframework.stereotype.Service;
- import com.baimi.routerweb.datasource.DataSourceContextHolder;
- import com.baimi.routerweb.datasource.DataSourceType;
- import com.baimi.routerweb.entity.User;
- import com.baimi.routerweb.mapper.UserMapper;
- import com.baimi.routerweb.service.UserService;
- @Service
- public class UserServiceImpl implements UserService {
- @Resource(name = "userMapper")
- private UserMapper userMapper;
- @Override
- public User getUser(String euserPhone) {
- DataSourceContextHolder. setDbType(DataSourceType.SOURCE_MOP);
- return userMapper.getUser(euserPhone);
- }
- }
12.寫Controller類,並在其中寫相對應的方法,給外部調用,這裏主要就是兩行代碼:注意每次要和數據庫打交道之前,切換到相對應的數據庫,我的DataSourceType. SOURCE_MOP="ds_mop"; 這裏的名字一定要和beans.xml裏面配置的數據源的名稱一樣
- //切換數據庫
- DataSourceContextHolder. setDbType(DataSourceType. SOURCE_MOP);
- //從數據庫中得到該用戶的數據
- User user= userService.getUser(userId);
整個Controller類的代碼
- import javax.annotation.Resource;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import net.sf.json.JSONObject;
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.RequestMapping;
- import com.baimi.routerweb.common.Constant;
- import com.baimi.routerweb.common.ErrorHandle;
- import com.baimi.routerweb.datasource.DataSourceContextHolder;
- import com.baimi.routerweb.datasource.DataSourceType;
- import com.baimi.routerweb.entity.User;
- import com.baimi.routerweb.service.UserService;
- import com.baimi.routerweb.util.HttpUtil;
- @Controller
- public class MainController {
- @Resource(name = "userServiceImpl")
- private UserService userService;
- @RequestMapping("/login.do")
- public String login(HttpServletRequest request, HttpServletResponse response) {
- // 獲取客戶端傳過來的code的值
- String code = request.getParameter( "code");
- if (code == null || "".equals(code)) {
- return ErrorHandle.getError(ErrorHandle.INVALID_TOKEN, "invalid token");
- }
- // 從微信得到token的值
- JSONObject objToken = HttpUtil.httpRequest(Constant.URL_WEIXIN_TOKEN, "GET", null);
- if (objToken == null || "".equals(objToken)) {
- return ErrorHandle.getError(ErrorHandle.SERVICE_UNRESPONSE, "service unresponse");
- }
- if (!objToken.has( "access_token")) {
- return ErrorHandle.getError(ErrorHandle.INVALID_TOKEN, "invalid token");
- }
- //根據token和code得到UserId
- JSONObject objUser = HttpUtil.httpRequest(Constant.URL_GET_USERID,
- "POST", "access_token=" + objToken.getString("access_token" )+ "&code=" + code + "&agentid=1");
- if(objUser== null|| "".equals(objUser)){
- return ErrorHandle.getError(ErrorHandle.SERVICE_UNRESPONSE, "service unresponse");
- }
- if(!objUser.has( "UserId")){
- return ErrorHandle.getError(ErrorHandle.INVALID_TOKEN, "invalid token");
- }
- String userId=objUser.getString( "UserId");
- //切換數據庫
- DataSourceContextHolder. setDbType(DataSourceType.SOURCE_MOP);
- //從數據庫中得到該用戶的數據
- User user= userService.getUser(userId);
- if(user!= null){
- JSONObject rtObj = new JSONObject();
- rtObj.put( "userId", String.valueOf(user.getUserId()));
- return rtObj.toString();
- }
- return ErrorHandle.getError(ErrorHandle.INVALID_USER,"invalid user");
- }
- }
2、另外一種方式就是spirng+JNDI方式,這種方式比較簡單,如果使用xml配置文件管理bean,可以使用此方式;
META-INF文件夾下面context.xml文件配置數據源,
<Resource name="jdbc/gpdw_route" auth="Container" type="javax.sql.DataSource"
username="search" password="search" driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://192.168.218.163:6432/dp_dw163" maxActive="10"
maxIdle="2" />
<Resource name="jdbc/gpdw_route2" auth="Container" type="javax.sql.DataSource"
username="bi_develop" password="gp163" driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://192.168.218.163:6432/dp_dw163" maxActive="10"
maxIdle="2" />
spring.xml配置事務等屬性,方便後面配置service dao的bean,首先定義jndi對象factorybean;
<bean id="greenPlumROUTE" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/gpdw_route</value>
</property>
<property name="resourceRef" value="true" />
</bean>
然後proxy代理datasource,
<bean id="dataSourceROUTE" class="net.sf.log4jdbc.Log4jdbcProxyDataSource">
<constructor-arg ref="greenPlumROUTE" />
</bean>
加入事務的管理類中,
<bean id="transactionManagerROUTE" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourceROUTE"></property>
</bean>
<!-- GreenPlum事務註解支持-->
<tx:annotation-driven transaction-manager="transactionManagerROUTE" />
這裏使用ibatis,所以要注入進來ibatis的配置文件,
<bean id="sqlSessionFactoryROUTE" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="/WEB-INF/postgre-ibatis.xml" />
<property name="mapperLocations"
value="classpath*:com/deppon/**/META-INF/ibatis/*.xml" />
<property name="dataSource" ref="dataSourceROUTE" />
</bean>
class="com.deppon.bi.module.route.server.dao.impl.TrunkParameterDao" scope="prototype">
<property name="sqlSessionFactory" ref="sqlSessionFactoryROUTE" />
</bean>