在微服务大行其道的今天,一个工程中同时操作多个不同的业务数据库这种情况已经很少见了,但并不意味不存在这样的需求。
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):
<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>
通过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切换实现逻辑如下:
/** * 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):
<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接口继承:
/** * 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"; }
继承示例代码如下:
/** * 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类的功能进行重新实现:
/** * 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。示例代码如下:
/** * 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 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的多个业务库管理支持的改造工作结束!
相关推荐
"spring+hibernate和spring+myBatis实现连接多个数据库,同时操作的项目"是针对这种需求的一个解决方案,旨在提供一种灵活且动态的数据源切换机制。 首先,Spring框架作为Java领域中最受欢迎的应用框架之一,其强大...
本实例主要探讨如何在MyBatis中实现与MySQL数据库的多对多关联,并利用Log4j进行日志记录,以确保操作的可追踪性和调试性。 首先,多对多关联通常需要一个中间表来存储两个表之间的关系。例如,假设我们有“学生”...
这个过程涵盖了Java Web开发的多个关键环节,对于理解和掌握Spring Boot与MyBatis的集成有极大的帮助。在实际开发中,你还可以进一步了解Spring Boot的自动配置、AOP、异常处理、安全控制等方面的知识,以及MyBatis...
这个入门项目实例将带你深入了解Mybatis的核心概念和基本用法。首先,我们来分析一下提供的文件内容。 1. **用户指南(图片文件)** - `111115114.jpg`、`1.png`、`2.png`、`3.png`:这些很可能是项目教程或步骤的...
在IT行业中,MyBatis是一个广泛应用的Java ORM(对象关系映射)框架,它使得开发者可以将数据库操作与业务逻辑代码解耦,提高了开发效率。本实例主要关注MyBatis如何实现增删改查(CRUD)操作,包括处理不同类型的表...
在MyBatis中,"多对一"关系映射是一种常见的数据库设计模式,它表示一个实体(如...通过理解和实践这个MyBatis多对一的实例,开发者能够更好地掌握如何在实际项目中处理复杂的数据库关系,提高数据操作的效率和灵活性。
这个经典入门实例旨在为初学者提供一个快速理解MyBatis基本概念和操作方式的平台。通过学习这个实例,你可以掌握如何在实际项目中使用MyBatis进行数据操作。 首先,我们需要了解MyBatis的核心概念。MyBatis的核心是...
MyBatis是一个强大的Java持久层框架,它与Hibernate和iBatis有所不同,更注重SQL的灵活性和手动控制。本教程将带你一步步构建MyBatis的第一个Demo,让你理解其基本概念和工作原理,这对于服务端初学者来说是必备的...
Mybatis是一款轻量级的Java持久层框架,它专注于SQL映射,简化了数据库操作,使得开发者可以直接编写原生SQL来操作数据库,从而避免了几乎所有的JDBC代码和手动设置参数以及获取结果集的麻烦。在Mybatis实例中,我们...
综上所述,这个项目实例展示了如何在Java环境中利用各种开源技术构建一个完整的数据操作解决方案,涵盖了网络通信、数据库管理和数据持久化等多个层面,是学习和理解这些技术如何协同工作的宝贵资源。
这个实例是一个图书管理系统的简单实现,涉及的技术栈包括Spring、MyBatis、Maven和MySQL。以下是详细步骤: **一、创建Maven Web项目** 1. 首先,我们需要创建一个基于Maven的Web项目。在IDE中,选择创建新项目,...
在这个名为"MybBatisStudy"的压缩包中,很可能是包含了一些关于Mybatis基本操作的代码示例,如增删改查(CRUD)等常见数据库交互任务。 首先,我们来看Mybatis的基本概念。Mybatis的核心组件有三个:...
MyBatis 是一个流行的 Java Persistence Framework,它提供了强大的数据库交互能力,而 MyCat 则是一个开源的数据库中间件,它可以将多个数据库集成到一起,提供统一的数据库访问接口。在本文中,我们将探讨如何使用...
2. **一对多关联**:假设存在两个表`t_customer`和`t_order`,`Customer`实体可以拥有多个`Order`实体。同样可以通过`resultMap`和`collection`元素实现一对多的关联映射。 - **Mapper XML文件**示例: ```xml ...
总的来说,这个实例为开发者提供了一个全面的参考,演示了如何在Spring Boot项目中同时管理和操作多种类型的数据存储,无论是关系型数据库(通过MyBatis和JPA),还是非关系型数据库(通过Redis和MongoDB)。...
映射文件中的每个`<select>`、`<insert>`、`<update>`或`<delete>`标签对应一个数据库操作。 接下来,`MyBatisDemo`可能是主程序,它展示了如何启动Mybatis并执行数据库操作。在Java代码中,你需要先创建...
6. **实体类**: 在本示例中,可能有一个或多个Java类代表数据库表的行,如User类。MyBatis通过这些类进行对象-关系映射。 7. **CRUD操作**: - **Create**(创建): 使用`insert`标签插入新记录,例如`...
图书管理系统的数据模型可能包括“图书”、“作者”、“出版社”等多个实体类,每个实体类对应数据库表的一张记录。实体类的设计应遵循面向对象原则,如封装、继承和多态,以提供更符合业务逻辑的接口。 在实际开发...
**多数据源切换** 的实现通常涉及配置多个DataSource实例,每个实例对应一个数据库。在Spring中,可以通过AbstractRoutingDataSource类来动态选择数据源。这个类可以根据某种上下文信息(如事务标识、请求参数等)来...
配置文件中还可以包含多个映射文件的位置,这些映射文件定义了SQL语句和结果映射。 2. **映射文件**:每个映射文件(如Mapper.xml)定义了一个Mapper接口,其中包含了SQL语句的定义。你可以使用XML标签来编写动态...