让mybatis支持管理和操作多个不同的业务数据库实例

在微服务大行其道的今天,一个工程中同时操作多个不同的业务数据库这种情况已经很少见了,但并不意味不存在这样的需求。

 

MyBatis世界上流行最广泛的SQL映射框架,由ClintonBegin在2002年创建,其后,捐献给了Apache基金会,成立了iBatis项目。 2010年5月,将代码库迁致GoogleCode,并更名为MyBatis。但是Mybatis对多个不同业务数据库的支持并没有因为从ibatis升级到mybatis过程中很好的集成原来ibatis项目中对多个数据库的支持。相反,mybatis对多数据库的管理能力相对较弱,接下来,我将详细说明如何让你的mybatis项目支持我们的多个不同业务数据库。

 

背景说明:当下有两个数据库dinner、customer通过同一个工程分别存储不同的业务数据。

 

配置SqlSessionFactoryBean信息(META-INF/spring/myteay-common-dal.xml):

 

Xml代码   收藏代码
  1. <bean id="dinnerSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  
  2.     <property name="dataSource" ref="myteayDinnerDataSource"></property>  
  3.     <property name="configLocation" value="classpath:/sqlmap/myteaydinner-sqlmap.xml" />  
  4. </bean>  
  5.   
  6. <bean id="customerSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  
  7.     <property name="dataSource" ref="myteayDataSource"></property>  
  8.     <property name="configLocation" value="classpath:/sqlmap/myteay-sqlmap.xml" />  
  9. </bean>  

 

 

通过org.mybatis.spring.SqlSessionFactoryBean对数据库和sqlmap的管理,最终SqlSessionFactoryBean会给我们一个org.apache.ibatis.session.defaults.DefaultSqlSessionFactory实例。

 

数据库操作过程中DAO通过集成org.mybatis.spring.support.SqlSessionDaoSupport类,利用对org.apache.ibatis.session.SqlSessionFactory实例,获取相应的DataSource实例进行对指定的数据库的数据管理工作。

 

问题也因此来了,在org.mybatis.spring.support.SqlSessionDaoSupport类中,org.apache.ibatis.session.SqlSessionFactory实例是作为类成员属性存在的,而打开org.mybatis.spring.support.SqlSessionDaoSupport类的源码分析发现,SqlSessionDaoSupport对通过SqlSessionFactory类构建的org.apache.ibatis.session.SqlSession实例管理提供了仅此一份的类实例,并未提供通过特定配置指定org.apache.ibatis.session.SqlSessionFactory实例的处理逻辑。

 

如果强行指定org.apache.ibatis.session.SqlSessionFactory实例未dinner库配置,这时由于customer数据库的配置也是通过org.mybatis.spring.support.SqlSessionDaoSupport类获取org.apache.ibatis.session.SqlSessionFactory实例的,这样就会导致customer数据库操作异常。

 

要想让SqlSessionDaoSupport类同时支持两种数据库实例,就需要为其补充进来一个切换策略。

 

SqlSessionFactory切换实现逻辑如下:

 

Java代码   收藏代码
  1. /** 
  2.  * Danlley Wei (mailto://danlley@126.com) 
  3.  * Copyright (c) 2005-2017 All Rights Reserved. 
  4.  */  
  5. package com.myteay.common.dal.utils;  
  6.   
  7. import java.util.Map;  
  8. import java.util.concurrent.ConcurrentHashMap;  
  9.   
  10. import org.apache.ibatis.session.SqlSessionFactory;  
  11. import org.apache.ibatis.session.defaults.DefaultSqlSessionFactory;  
  12. import org.springframework.util.CollectionUtils;  
  13.   
  14. import com.myteay.common.util.comm.StringUtils;  
  15.   
  16. /** 
  17.  * SqlSessionFactory会话实例管理组件 
  18.  *  
  19.  * @author danlley(danlley@126.com) 
  20.  * @version $Id: SqlSession.java, v 0.1 2017年5月7日 上午12:40:16 danlley(danlley@126.com) Exp $ 
  21.  */  
  22. public class SqlSessionSwitcher {  
  23.   
  24.     /** 用于指定DefaultSqlSessionFactory,线程安全 */  
  25.     private Map<String, DefaultSqlSessionFactory> switcherBeans = new ConcurrentHashMap<String, DefaultSqlSessionFactory>();  
  26.   
  27.     /** 
  28.      * 获取指定的SqlSessionFactory 
  29.      *  
  30.      * @param key 
  31.      * @return 
  32.      */  
  33.     public SqlSessionFactory getSqlSessionFactory(String key) {  
  34.         if (StringUtils.isBlank(key) || CollectionUtils.isEmpty(switcherBeans) || !switcherBeans.containsKey(key)) {  
  35.             throw new IllegalArgumentException("SqlSessionSwitcher初始化失败,无法得到可用的SqlSessionFactory实例 key=" + key);  
  36.         }  
  37.   
  38.         return switcherBeans.get(key);  
  39.     }  
  40.   
  41.     /** 
  42.      * Setter method for property <tt>switcherBeans</tt>. 
  43.      *  
  44.      * @param switcherBeans value to be assigned to property switcherBeans 
  45.      */  
  46.     public void setSwitcherBeans(Map<String, DefaultSqlSessionFactory> switcherBeans) {  
  47.         this.switcherBeans = switcherBeans;  
  48.     }  
  49. }  

 

 

对应配置信息如下(META-INF/spring/myteay-common-dal.xml):

 

Xml代码   收藏代码
  1. <bean id="switcher" class="com.myteay.common.dal.utils.SqlSessionSwitcher">  
  2.     <property name="switcherBeans">  
  3.         <map>  
  4.             <entry key="dinnerSqlSessionFactory" value-ref="dinnerSqlSessionFactory"></entry>  
  5.             <entry key="customerSqlSessionFactory" value-ref="customerSqlSessionFactory"></entry>  
  6.         </map>  
  7.     </property>  
  8. </bean>  

 

 

通过上面的处理,我们首先得到了一个针对不同数据库的完整SqlSessionFactory实例集合。

 

为了能够让每个DAO实现类能够识别获取指定的SqlSessionFactory实例,我们定义一个常量接口,方便DAO接口继承:

 

Java代码   收藏代码
  1. /** 
  2.  * Danlley Wei (mailto://danlley@126.com) 
  3.  * Copyright (c) 2005-2017 All Rights Reserved. 
  4.  */  
  5. package com.myteay.common.dal.utils;  
  6.   
  7. /** 
  8.  * 各个DAO类继承此类,以便能够得到指定的数据库 
  9.  *  
  10.  * @author danlley(danlley@126.com) 
  11.  * @version $Id: MtDBKey.java, v 0.1 2017年5月7日 上午2:08:07 danlley(danlley@126.com) Exp $ 
  12.  */  
  13. public interface MtDBKey {  
  14.   
  15.     /** dinner库标识 */  
  16.     public final static String dinner   = "dinnerSqlSessionFactory";  
  17.   
  18.     /** customer库标识 */  
  19.     public final static String customer = "customerSqlSessionFactory";  
  20. }  

 

 

继承示例代码如下:

 

Java代码   收藏代码
  1. /** 
  2.  * Myteay.com Inc. 
  3.  * Copyright (c) 2015-2015 All Rights Reserved. 
  4.  */  
  5. package com.myteay.common.dal.daointerface;  
  6.   
  7. import com.myteay.common.dal.dataobject.UsersInfoDO;  
  8. import com.myteay.common.dal.utils.MtDBKey;  
  9.   
  10. /** 
  11.  * 用户基本信息操作DAO 
  12.  *  
  13.  * @author Administrator 
  14.  * @version $Id: UsersInfoDAO.java, v 0.1 2015年11月15日 下午4:37:30 Administrator Exp $ 
  15.  */  
  16. public interface UsersInfoDAO extends MtDBKey {  
  17.   
  18.     /** 
  19.      * 通过userid查找用户信息 
  20.      *  
  21.      * @param userID    会员ID 
  22.      * @return 
  23.      */  
  24.     UsersInfoDO getById(String userId);  
  25. }  

 

 

为了能够让DAO实现类获取操作特定数据库的能力,我们对org.mybatis.spring.support.SqlSessionDaoSupport类的功能进行重新实现:

 

Java代码   收藏代码
  1. /** 
  2.  * Danlley Wei (mailto://danlley@126.com) 
  3.  * Copyright (c) 2005-2017 All Rights Reserved. 
  4.  */  
  5. package com.myteay.common.dal.utils;  
  6.   
  7. import org.apache.ibatis.session.SqlSession;  
  8. import org.apache.ibatis.session.SqlSessionFactory;  
  9. import org.mybatis.spring.SqlSessionTemplate;  
  10. import org.springframework.beans.factory.annotation.Autowired;  
  11. import org.springframework.dao.support.DaoSupport;  
  12.   
  13. /** 
  14.  * 本类参考了org.mybatis.spring.support.SqlSessionDaoSupport类的实现,但解决了多数据源管理的问题 
  15.  *  
  16.  * @see org.mybatis.spring.support.SqlSessionDaoSupport 
  17.  * @author danlley(danlley@126.com) 
  18.  * @version $Id: MtSqlSessionDaoSupport.java, v 0.1 2017年5月7日 上午12:35:28 danlley(danlley@126.com) Exp $ 
  19.  */  
  20. public class MtSqlSessionDaoSupport extends DaoSupport {  
  21.   
  22.     /** 数据库切换管理器 */  
  23.     @Autowired  
  24.     private SqlSessionSwitcher switcher;  
  25.   
  26.     /** SQL会话 */  
  27.     private SqlSession         sqlSession;  
  28.   
  29.     /** 外部SQL会话标识 */  
  30.     private boolean            externalSqlSession = false;  
  31.   
  32.     /** 
  33.      * 初始化SQL会话 
  34.      *  
  35.      * @param sqlSessionFactory 
  36.      */  
  37.     public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {  
  38.         if (!this.externalSqlSession) {  
  39.             //this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);  
  40.         }  
  41.     }  
  42.   
  43.     /** 
  44.      * SQL会话 
  45.      *  
  46.      * @param sqlSessionTemplate 
  47.      */  
  48.     public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {  
  49.         //this.sqlSession = sqlSessionTemplate;  
  50.         // this.externalSqlSession = true;  
  51.     }  
  52.   
  53.     /** 
  54.      * Users should use this method to get a SqlSession to call its statement methods 
  55.      * This is SqlSession is managed by spring. Users should not commit/rollback/close it 
  56.      * because it will be automatically done. 
  57.      * 
  58.      * @return Spring managed thread safe SqlSession 
  59.      * @throws Exception  
  60.      */  
  61.     public SqlSession getSqlSession(String key) {  
  62.   
  63.         if (sqlSession != null) {  
  64.             return this.sqlSession;  
  65.         }  
  66.   
  67.         //防止线程多次对实例进行不必要的初始化  
  68.         if (switcher == null || switcher.getSqlSessionFactory(key) == null) {  
  69.             throw new IllegalArgumentException(  
  70.                 "Property 'sqlSessionFactory' or 'sqlSessionTemplate' or 'switcher' are required");  
  71.         }  
  72.   
  73.         sqlSession = new SqlSessionTemplate(switcher.getSqlSessionFactory(key));  
  74.   
  75.         return this.sqlSession;  
  76.     }  
  77.   
  78.     /** 
  79.      * {@inheritDoc} 
  80.      */  
  81.     @Override  
  82.     protected void checkDaoConfig() {  
  83.         //notNull(this.sqlSession, "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required");  
  84.     }  
  85.   
  86.     /** 
  87.      * Setter method for property <tt>switcher</tt>. 
  88.      *  
  89.      * @param switcher value to be assigned to property switcher 
  90.      */  
  91.     public void setSwitcher(SqlSessionSwitcher switcher) {  
  92.         this.switcher = switcher;  
  93.     }  
  94.   
  95. }  

 

 

 

接下来,DAO接口的实现类不再需要继承org.mybatis.spring.support.SqlSessionDaoSupport类,转而继承我们重新改写的类com.myteay.common.dal.utils.MtSqlSessionDaoSupport。示例代码如下:

Java代码   收藏代码
  1. /** 
  2.  * Myteay.com Inc. 
  3.  * Copyright (c) 2015-2015 All Rights Reserved. 
  4.  */  
  5. package com.myteay.common.dal.ibatis;  
  6.   
  7. import com.myteay.common.dal.daointerface.UsersInfoDAO;  
  8. import com.myteay.common.dal.dataobject.UsersInfoDO;  
  9. import com.myteay.common.dal.utils.MtSqlSessionDaoSupport;  
  10.   
  11. /** 
  12.  * 用户基本信息操作DAO 
  13.  *  
  14.  * @author Administrator 
  15.  * @version $Id: IbatisUsersInfoDAO.java, v 0.1 2015年11月15日 下午4:37:30 Administrator Exp $ 
  16.  */  
  17. public class IbatisUsersInfoDAO extends MtSqlSessionDaoSupport implements UsersInfoDAO {  
  18.   
  19.     /**  
  20.      * @see com.myteay.common.dal.daointerface.UsersInfoDAO#getById(java.lang.String) 
  21.      */  
  22.     @Override  
  23.     public UsersInfoDO getById(String userId) {  
  24.         return (UsersInfoDO) this.getSqlSession(customer).selectOne("MS-MT-USER-INFO-GET-BY-ID", userId);  
  25.     }  
  26.   
  27. }  

 

最后,不失完整性,贴出整体的配置信息(META-INF/spring/myteay-common-dal.xml):

Xml代码   收藏代码
  1. <?xml version="1.0" encoding="GBK"?>  
  2.   
  3. <beans xmlns="http://www.springframework.org/schema/beans"    
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"    
  5.     xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"    
  6.     xsi:schemaLocation="    
  7.         http://www.springframework.org/schema/beans    
  8.         http://www.springframework.org/schema/beans/spring-beans-4.0.xsd    
  9.         http://www.springframework.org/schema/context    
  10.         http://www.springframework.org/schema/context/spring-context-4.0.xsd    
  11.         http://www.springframework.org/schema/tx    
  12.         http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"    
  13. default-autowire="byName">  
  14.     <!-- ============================================================================ -->  
  15.     <!-- ============================  DataSource配置   =============================== -->  
  16.     <!-- ============================================================================ -->  
  17.     <!-- 会员数据库 -->  
  18.     <bean id="myteayDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">  
  19.         <property name="driverClassName">  
  20.             <value>org.gjt.mm.mysql.Driver</value>  
  21.         </property>  
  22.         <property name="url">  
  23.             <value>jdbc:mysql://192.168.56.101:3306/customers?useUnicode=true&amp;characterEncoding=gbk</value>  
  24.         </property>  
  25.         <property name="username">  
  26.             <value>customers</value>  
  27.         </property>  
  28.         <property name="password">  
  29.             <value>*******</value>  
  30.         </property>  
  31.     </bean>  
  32.     <!-- 业务配置库 -->  
  33.     <bean id="myteayDinnerDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">  
  34.         <property name="driverClassName">  
  35.             <value>org.gjt.mm.mysql.Driver</value>  
  36.         </property>  
  37.         <property name="url">  
  38.             <value>jdbc:mysql://192.168.56.101:3306/dinner?useUnicode=true&amp;characterEncoding=gbk</value>  
  39.         </property>  
  40.         <property name="username">  
  41.             <value>dinner</value>  
  42.         </property>  
  43.         <property name="password">  
  44.             <value>*******</value>  
  45.         </property>  
  46.     </bean>  
  47.     <!-- ============================================================================ -->  
  48.     <!-- ===================       SqlSessionFactoryBean配置           ===================== -->  
  49.     <!-- ============================================================================ -->  
  50.     <bean id="dinnerSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  
  51.         <property name="dataSource" ref="myteayDinnerDataSource"></property>  
  52.         <property name="configLocation" value="classpath:/sqlmap/myteaydinner-sqlmap.xml" />  
  53.     </bean>  
  54.   
  55.     <bean id="customerSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  
  56.         <property name="dataSource" ref="myteayDataSource"></property>  
  57.         <property name="configLocation" value="classpath:/sqlmap/myteay-sqlmap.xml" />  
  58.     </bean>  
  59.   
  60.   
  61.     <!-- ============================================================================ -->  
  62.     <!-- ================== TransactionTemplate和TransactionManager配置 ============== -->  
  63.     <!-- ============================================================================ -->  
  64.     <!-- transactionManager -->  
  65.     <bean id="dinnerTxManager"  
  66.         class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
  67.         <property name="dataSource" ref="myteayDinnerDataSource"></property>  
  68.     </bean>  
  69.     <tx:annotation-driven transaction-manager="dinnerTxManager" />  
  70.   
  71.     <!-- transactionManager -->  
  72.     <bean id="customerTxManager"  
  73.         class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
  74.         <property name="dataSource" ref="myteayDataSource"></property>  
  75.     </bean>  
  76.     <tx:annotation-driven transaction-manager="customerTxManager" />  
  77.       
  78.     <bean id="myteayDinnerTransactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">  
  79.         <property name="transactionManager">  
  80.             <ref bean="dinnerTxManager"/>  
  81.         </property>  
  82.     </bean>  
  83.     <bean id="myteayCustomerTransactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">  
  84.         <property name="transactionManager">  
  85.             <ref bean="customerTxManager"/>  
  86.         </property>  
  87.     </bean>  
  88.     <bean id="switcher" class="com.myteay.common.dal.utils.SqlSessionSwitcher">  
  89.         <property name="switcherBeans">  
  90.             <map>  
  91.                 <entry key="dinnerSqlSessionFactory" value-ref="dinnerSqlSessionFactory"></entry>  
  92.                 <entry key="customerSqlSessionFactory" value-ref="customerSqlSessionFactory"></entry>  
  93.             </map>  
  94.         </property>  
  95.     </bean>  
  96. </beans>  

 

至此,针对mybatis的多个业务库管理支持的改造工作结束!


文章源址  http://danlley.iteye.com/blog/2373036



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值