您的位置:首页 > 数据库

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

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

 

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代码  


<bean id="dinnerSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  

    <property name="dataSource" ref="myteayDinnerDataSource"></property>  <
4000
/li>
    <property name="configLocation" value="classpath:/sqlmap/myteaydinner-sqlmap.xml" />  

</bean>  

  

<bean id="customerSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  

    <property name="dataSource" ref="myteayDataSource"></property>  

    <property name="configLocation" value="classpath:/sqlmap/myteay-sqlmap.xml" />  

</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代码  


/** 

 * Danlley Wei (mailto://danlley@126.com) 

 * Copyright (c) 2005-2017 All Rights Reserved. 

 */  

package com.myteay.common.dal.utils;  

  

import java.util.Map;  

import java.util.concurrent.ConcurrentHashMap;  

  

import org.apache.ibatis.session.SqlSessionFactory;  

import org.apache.ibatis.session.defaults.DefaultSqlSessionFactory;  

import org.springframework.util.CollectionUtils;  

  

import com.myteay.common.util.comm.StringUtils;  

  

/** 

 * SqlSessionFactory会话实例管理组件 

 *  

 * @author danlley(danlley@126.com) 

 * @version $Id: SqlSession.java, v 0.1 2017年5月7日 上午12:40:16 danlley(danlley@126.com) Exp $ 

 */  

public class SqlSessionSwitcher {  

  

    /** 用于指定DefaultSqlSessionFactory,线程安全 */  

    private Map<String, DefaultSqlSessionFactory> switcherBeans = new ConcurrentHashMap<String, DefaultSqlSessionFactory>();  

  

    /** 

     * 获取指定的SqlSessionFactory 

     *  

     * @param key 

     * @return 

     */  

    public SqlSessionFactory getSqlSessionFactory(String key) {  

        if (StringUtils.isBlank(key) || CollectionUtils.isEmpty(switcherBeans) || !switcherBeans.containsKey(key)) {  

            throw new IllegalArgumentException("SqlSessionSwitcher初始化失败,无法得到可用的SqlSessionFactory实例 key=" + key);  

        }  

  

        return switcherBeans.get(key);  

    }  

  

    /** 

     * Setter method for property <tt>switcherBeans</tt>. 

     *  

     * @param switcherBeans value to be assigned to property switcherBeans 

     */  

    public void setSwitcherBeans(Map<String, DefaultSqlSessionFactory> switcherBeans) {  

        this.switcherBeans = switcherBeans;  

    }  

}  

 

 

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

 

Xml代码  


<bean id="switcher" class="com.myteay.common.dal.utils.SqlSessionSwitcher">  

    <property name="switcherBeans">  

        <map>  

            <entry key="dinnerSqlSessionFactory" value-ref="dinnerSqlSessionFactory"></entry>  

            <entry key="customerSqlSessionFactory" value-ref="customerSqlSessionFactory"></entry>  

        </map>  

    </property>  

</bean>  

 

 

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

 

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

 

Java代码  


/** 

 * Danlley Wei (mailto://danlley@126.com) 

 * Copyright (c) 2005-2017 All Rights Reserved. 

 */  

package com.myteay.common.dal.utils;  

  

/** 

 * 各个DAO类继承此类,以便能够得到指定的数据库 

 *  

 * @author danlley(danlley@126.com) 

 * @version $Id: MtDBKey.java, v 0.1 2017年5月7日 上午2:08:07 danlley(danlley@126.com) Exp $ 

 */  

public interface MtDBKey {  

  

    /** dinner库标识 */  

    public final static String dinner   = "dinnerSqlSessionFactory";  

  

    /** customer库标识 */  

    public final static String customer = "customerSqlSessionFactory";  

}  

 

 

继承示例代码如下:

 

Java代码  


/** 

 * Myteay.com Inc. 

 * Copyright (c) 2015-2015 All Rights Reserved. 

 */  

package com.myteay.common.dal.daointerface;  

  

import com.myteay.common.dal.dataobject.UsersInfoDO;  

import com.myteay.common.dal.utils.MtDBKey;  

  

/** 

 * 用户基本信息操作DAO 

 *  

 * @author Administrator 

 * @version $Id: UsersInfoDAO.java, v 0.1 2015年11月15日 下午4:37:30 Administrator Exp $ 

 */  

public interface UsersInfoDAO extends MtDBKey {  

  

    /** 

     * 通过userid查找用户信息 

     *  

     * @param userID    会员ID 

     * @return 

     */  

    UsersInfoDO getById(String userId);  

}  

 

 

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

 

Java代码  


/** 

 * Danlley Wei (mailto://danlley@126.com) 

 * Copyright (c) 2005-2017 All Rights Reserved. 

 */  

package com.myteay.common.dal.utils;  

  

import org.apache.ibatis.session.SqlSession;  

import org.apache.ibatis.session.SqlSessionFactory;  

import org.mybatis.spring.SqlSessionTemplate;  

import org.springframework.beans.factory.annotation.Autowired;  

import org.springframework.dao.support.DaoSupport;  

  

/** 

 * 本类参考了org.mybatis.spring.support.SqlSessionDaoSupport类的实现,但解决了多数据源管理的问题 

 *  

 * @see org.mybatis.spring.support.SqlSessionDaoSupport 

 * @author danlley(danlley@126.com) 

 * @version $Id: MtSqlSessionDaoSupport.java, v 0.1 2017年5月7日 上午12:35:28 danlley(danlley@126.com) Exp $ 

 */  

public class MtSqlSessionDaoSupport extends DaoSupport {  

  

    /** 数据库切换管理器 */  

    @Autowired  

    private SqlSessionSwitcher switcher;  

  

    /** SQL会话 */  

    private SqlSession         sqlSession;  

  

    /** 外部SQL会话标识 */  

    private boolean            externalSqlSession = false;  

  

    /** 

     * 初始化SQL会话 

     *  

     * @param sqlSessionFactory 

     */  

    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {  

        if (!this.externalSqlSession) {  

            //this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);  

        }  

    }  

  

    /** 

     * SQL会话 

     *  

     * @param sqlSessionTemplate 

     */  

    public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {  

        //this.sqlSession = sqlSessionTemplate;  

        // this.externalSqlSession = true;  

    }  

  

    /** 

     * Users should use this method to get a SqlSession to call its statement methods 

     * This is SqlSession is managed by spring. Users should not commit/rollback/close it 

     * because it will be automatically done. 

     * 

     * @return Spring managed thread safe SqlSession 

     * @throws Exception  

     */  

    public SqlSession getSqlSession(String key) {  

  

        if (sqlSession != null) {  

            return this.sqlSession;  

        }  

  

        //防止线程多次对实例进行不必要的初始化  

        if (switcher == null || switcher.getSqlSessionFactory(key) == null) {  

            throw new IllegalArgumentException(  

                "Property 'sqlSessionFactory' or 'sqlSessionTemplate' or 'switcher' are required");  

        }  

  

        sqlSession = new SqlSessionTemplate(switcher.getSqlSessionFactory(key));  

  

        return this.sqlSession;  

    }  

  

    /** 

     * {@inheritDoc} 

     */  

    @Override  

    protected void checkDaoConfig() {  

        //notNull(this.sqlSession, "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required");  

    }  

  

    /** 

     * Setter method for property <tt>switcher</tt>. 

     *  

     * @param switcher value to be assigned to property switcher 

     */  

    public void setSwitcher(SqlSessionSwitcher switcher) {  

        this.switcher = switcher;  

    }  

  

}  

 

 

 

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

Java代码  


/** 

 * Myteay.com Inc. 

 * Copyright (c) 2015-2015 All Rights Reserved. 

 */  

package com.myteay.common.dal.ibatis;  

  

import com.myteay.common.dal.daointerface.UsersInfoDAO;  

import com.myteay.common.dal.dataobject.UsersInfoDO;  

import com.myteay.common.dal.utils.MtSqlSessionDaoSupport;  

  

/** 

 * 用户基本信息操作DAO 

 *  

 * @author Administrator 

 * @version $Id: IbatisUsersInfoDAO.java, v 0.1 2015年11月15日 下午4:37:30 Administrator Exp $ 

 */  

public class IbatisUsersInfoDAO extends MtSqlSessionDaoSupport implements UsersInfoDAO {  

  

    /**  

     * @see com.myteay.common.dal.daointerface.UsersInfoDAO#getById(java.lang.String) 

     */  

    @Override  

    public UsersInfoDO getById(String userId) {  

        return (UsersInfoDO) this.getSqlSession(customer).selectOne("MS-MT-USER-INFO-GET-BY-ID", userId);  

    }  

  

}  

 

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

Xml代码  


<?xml version="1.0" encoding="GBK"?>  

  

<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:tx="http://www.springframework.org/schema/tx"    

    xsi:schemaLocation="    

        http://www.springframework.org/schema/beans    

        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd    

        http://www.springframework.org/schema/context    

        http://www.springframework.org/schema/context/spring-context-4.0.xsd    

        http://www.springframework.org/schema/tx    

        http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"    

default-autowire="byName">  

    <!-- ============================================================================ -->  

    <!-- ============================  DataSource配置   =============================== -->  

    <!-- ============================================================================ -->  

    <!-- 会员数据库 -->  

    <bean id="myteayDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">  

        <property name="driverClassName">  

            <value>org.gjt.mm.mysql.Driver</value>  

        </property>  

        <property name="url">  

            <value>jdbc:mysql://192.168.56.101:3306/customers?useUnicode=true&characterEncoding=gbk</value>  

        </property>  

        <property name="username">  

            <value>customers</value>  

        </property>  

        <property name="password">  

            <value>*******</value>  

        </property>  

    </bean>  

    <!-- 业务配置库 -->  

    <bean id="myteayDinnerDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">  

        <property name="driverClassName">  

            <value>org.gjt.mm.mysql.Driver</value>  

        </property>  

        <property name="url">  

            <value>jdbc:mysql://192.168.56.101:3306/dinner?useUnicode=true&characterEncoding=gbk</value>  

        </property>  

        <property name="username">  

            <value>dinner</value>  

        </property>  

        <property name="password">  

            <value>*******</value>  

        </property>  

    </bean>  

    <!-- ============================================================================ -->  

    <!-- ===================       SqlSessionFactoryBean配置           ===================== -->  

    <!-- ============================================================================ -->  

    <bean id="dinnerSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  

        <property name="dataSource" ref="myteayDinnerDataSource"></property>  

        <property name="configLocation" value="classpath:/sqlmap/myteaydinner-sqlmap.xml" />  

    </bean>  

  

    <bean id="customerSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  

        <property name="dataSource" ref="myteayDataSource"></property>  

        <property name="configLocation" value="classpath:/sqlmap/myteay-sqlmap.xml" />  

    </bean>  

  

  

    <!-- ============================================================================ -->  

    <!-- ================== TransactionTemplate和TransactionManager配置 ============== -->  

    <!-- ============================================================================ -->  

    <!-- transactionManager -->  

    <bean id="dinnerTxManager"  

        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  

        <property name="dataSource" ref="myteayDinnerDataSource"></property>  

    </bean>  

    <tx:annotation-driven transaction-manager="dinnerTxManager" />  

  

    <!-- transactionManager -->  

    <bean id="customerTxManager"  

        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  

        <property name="dataSource" ref="myteayDataSource"></property>  

    </bean>  

    <tx:annotation-driven transaction-manager="customerTxManager" />  

      

    <bean id="myteayDinnerTransactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">  

        <property name="transactionManager">  

            <ref bean="dinnerTxManager"/>  

        </property>  

    </bean>  

    <bean id="myteayCustomerTransactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">  

        <property name="transactionManager">  

            <ref bean="customerTxManager"/>  

        </property>  

    </bean>  

    <bean id="switcher" class="com.myteay.common.dal.utils.SqlSessionSwitcher">  

        <property name="switcherBeans">  

            <map>  

                <entry key="dinnerSqlSessionFactory" value-ref="dinnerSqlSessionFactory"></entry>  

                <entry key="customerSqlSessionFactory" value-ref="customerSqlSessionFactory"></entry>  

            </map>  

        </property>  

    </bean>  

</beans>  

 

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

文章源址  http://danlley.iteye.com/blog/2373036
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐