Spring+Mybatis多数据源配置(二)——databaseIdProvider的使用

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介:  在上一篇同系列的博文中,讲到配置多数据源,然后根据config.properties配置不同的数据库,进行切换。而且需要根据不同的数据库,配置不同的mybatis sql映射配置文件,如下: classpath...

 在上一篇同系列的博文中,讲到配置多数据源,然后根据config.properties配置不同的数据库,进行切换。而且需要根据不同的数据库,配置不同的mybatis sql映射配置文件,如下:

        <property name="mapperLocations">
            <list>
                <value>classpath:com/shr/dao/resources/${dataSource}mappers/*_mapper.xml</value>
            </list>
        </property>
    这样根据dataSource名称匹配不同的mybatis sql映射配置文件,大家都知道mysql和oracle是有一些语法差异的,但是大多数的语法是一样的,我们能否只针对这些有语法差异的sql语句进行多重配置,其余的相同的语法的就使用同一份配置呢?答案当然是肯定的。
这里需要应用到mybatis的org.apache.ibatis.mapping.VendorDatabaseIdProvider。通过在mybatis sql映射配置文件中添加databaseId的属性,来区分不同的数据库。
    举个例子:
    <resultMap id="userResultMap" type="com.shr.dao.model.userManage.UserInfo">
        <result property="user_id" column="user_id"/>
        <result property="user_name" column="user_name"/>
        <result property="user_password" column="user_password"/>
        <result property="user_privilege" column="user_privilege"/>
        <result property="user_alias" column="user_alias"/>
        <result property="create_date" column="create_date" javaType="java.util.Date" jdbcType="TIMESTAMP"/>
        <result property="invalid_date" column="invalid_date" javaType="java.util.Date" jdbcType="TIMESTAMP"/>
    </resultMap>
    <select id="selectUserInfo" resultMap="userResultMap" databaseId="mysql">
        select user_id, user_name, user_password, user_privilege, user_alias, create_date, invalid_date from user_define order by user_id asc
    </select>
    <select id="selectUserInfo" resultMap="userResultMap" databaseId="oracle">
        select user_id, user_name, user_password, user_privilege, user_alias, create_date, invalid_date from user_define order by user_id desc
    </select>
上面是一个获取用户信息的sql语句,可以看到mysql和oracle的sql语句有略微的差异(asc和desc),当配置文件config.properties中的dataSource字段配置为mysql或者为oracle时都可以获取相应的结果。当dataSource配置为oracle然后在上面的代码中删掉:
    <select id="selectUserInfo" resultMap="userResultMap" databaseId="oracle">
        select user_id, user_name, user_password, user_privilege, user_alias, create_date, invalid_date from user_define order by user_id desc
    </select>
这一段内容,运行测试用例:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("file:WebContent/WEB-INF/applicationContext.xml")
    @Transactional
    @TransactionConfiguration(transactionManager="transactionManager",defaultRollback=false)
    public class UserManageServiceTest {

        @Inject
        private UserManageService userManageService;

        @Test
        public void testGetUserListInfo()
        {
            List<UserListInfo> list = userManageService.getUserListInfo();
            for(UserListInfo user : list)
            {
                System.out.println(user.getUser_name());
            }
        }
    }
会报如下错误:
    org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.shr.dao.mapper.IuserManageMapper.selectUserInfo
    at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:189)
    at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:43)
    at org.apache.ibatis.binding.MapperProxy.cachedMapperMethod(MapperProxy.java:58)
    at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:51)
    at com.sun.proxy.$Proxy29.selectUserInfo(Unknown Source)
    at com.shr.service.userManage.UserManageService.getUserListInfo(UserManageService.java:98)
    at com.shr.service.userManage.UserManageServiceTest.testGetUserListInfo(UserManageServiceTest.java:35)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
通过报错信息,大概可以知道没有相应的配置映射关系。由此可以证明(把config.properties中的dataSource配置成mysql然后删掉databaseId="mysql"的配置,结果也会报相同的错误),mysql对应的是databaseId="mysql"的sql语句,而oracle对应的是databaseId="oracle"的配置语句。或者如果两个数据库中用户表数据是相同的话,通过测试用例打印出来的用户名称一个是正序一个是倒序,也可以得出相同的结论。
    最后奉上applicationContext.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:aop="http://www.springframework.org/schema/aop" 
        xmlns:tx="http://www.springframework.org/schema/tx" 
        xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        classpath:/org/springframework/beans/factory/xml/spring-beans-3.0.xsd
        http://www.springframework.org/schema/aop 
        classpath:/org/springframework/aop/config/spring-aop-3.0.xsd
        http://www.springframework.org/schema/context
        classpath:/org/springframework/context/config/spring-context-3.0.xsd
        http://www.springframework.org/schema/tx 
        classpath:/org/springframework/transaction/config/spring-tx-3.0.xsd">

    <!-- IoC配置 -->
    <!-- 扫描类包,将标注Spring注解的类自动转化Bean,同时完成Bean的注入 -->
    <context:component-scan base-package="com.shr.dao" />
    <context:component-scan base-package="com.shr.service" />
    
    <!-- DAO配置 -->
    <context:property-placeholder location="classpath:config.properties"/>
    <bean id="mysql" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName"    value="${mysql_driver}"/>
        <property name="url"        value="${mysql_url}"/>
        <property name="username"   value="${mysql_username}"/>
        <property name="password"   value="${mysql_password}"/>
    </bean>
    <bean id="oracle" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName"    value="${ora_driver}"/>
        <property name="url"        value="${ora_url}"/>
        <property name="username"   value="${ora_username}"/>
        <property name="password"   value="${ora_password}"/>
    </bean>

    <bean id="vendorProperties"
        class="org.springframework.beans.factory.config.PropertiesFactoryBean">
        <property name="properties">
            <props>
                <prop key="Oracle">oracle</prop>
                <prop key="MySQL">mysql</prop>
            </props>
        </property>
    </bean>

    <bean id="databaseIdProvider" class="org.apache.ibatis.mapping.VendorDatabaseIdProvider">
        <property name="properties" ref="vendorProperties" />
    </bean>
    <bean name="myBatisSQLInterceptor" class="com.shr.dao.MyBatisSQLInterceptor"></bean>
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="${dataSource}" />
        <property name="typeAliasesPackage" value="com.shr.dao.pojo,com.shr.dao.model" />
        <property name="databaseIdProvider" ref="databaseIdProvider" />
        <property name="mapperLocations">
            <list>
                <value>classpath:com/shr/dao/resources/mappers/*_mapper.xml</value>
            </list>
        </property>
        <!-- <property name="configLocation" value="/WEB-INF/mybatis-config.xml"/> -->
        <property name="typeHandlersPackage" value="com.shr.dao" />
        <property name="plugins">
            <list>
                <ref bean="myBatisSQLInterceptor"/>
            </list>
        </property>
    </bean>
    
    <!-- 配置事务管理器 -->
    <tx:annotation-driven/>
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="${dataSource}"/>
    </bean>
    
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.shr.dao.mapper"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> 
        <!-- <property name="markerInterface" value="com.shr.dao.mapper.ITemplateMapper"/> -->
    </bean>   
</beans>


相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
1月前
|
XML Java 测试技术
Spring IOC—基于注解配置和管理Bean 万字详解(通俗易懂)
Spring 第三节 IOC——基于注解配置和管理Bean 万字详解!
130 26
|
3月前
|
Java Spring
【Spring】方法注解@Bean,配置类扫描路径
@Bean方法注解,如何在同一个类下面定义多个Bean对象,配置扫描路径
191 73
|
2月前
|
SQL Java 数据库连接
对Spring、SpringMVC、MyBatis框架的介绍与解释
Spring 框架提供了全面的基础设施支持,Spring MVC 专注于 Web 层的开发,而 MyBatis 则是一个高效的持久层框架。这三个框架结合使用,可以显著提升 Java 企业级应用的开发效率和质量。通过理解它们的核心特性和使用方法,开发者可以更好地构建和维护复杂的应用程序。
137 29
|
2月前
|
监控 Java 数据库连接
Spring c3p0配置详解
在Spring项目中配置C3P0数据源,可以显著提高数据库连接的效率和应用程序的性能。通过合理的配置和优化,可以充分发挥C3P0的优势,满足不同应用场景的需求。希望本文的详解和示例代码能为开发者提供清晰的指导,帮助实现高效的数据库连接管理。
106 10
|
2月前
|
前端开发 Java 数据库连接
Java后端开发-使用springboot进行Mybatis连接数据库步骤
本文介绍了使用Java和IDEA进行数据库操作的详细步骤,涵盖从数据库准备到测试类编写及运行的全过程。主要内容包括: 1. **数据库准备**:创建数据库和表。 2. **查询数据库**:验证数据库是否可用。 3. **IDEA代码配置**:构建实体类并配置数据库连接。 4. **测试类编写**:编写并运行测试类以确保一切正常。
90 2
|
2月前
|
SQL JavaScript Java
Spring Boot 3 整合 Mybatis-Plus 实现数据权限控制
本文介绍了如何在Spring Boot 3中整合MyBatis-Plus实现数据权限控制,通过使用MyBatis-Plus提供的`DataPermissionInterceptor`插件,在不破坏原有代码结构的基础上实现了细粒度的数据访问控制。文中详细描述了自定义注解`DataScope`的使用方法、`DataPermissionHandler`的具体实现逻辑,以及根据用户的不同角色和部门动态添加SQL片段来限制查询结果。此外,还展示了基于Spring Boot 3和Vue 3构建的前后端分离快速开发框架的实际应用案例,包括项目的核心功能模块如用户管理、角色管理等,并提供Gitee上的开源仓库
373 11
|
2月前
|
缓存 NoSQL Java
Mybatis学习:Mybatis缓存配置
MyBatis缓存配置包括一级缓存(事务级)、二级缓存(应用级)和三级缓存(如Redis,跨JVM)。一级缓存自动启用,二级缓存需在`mybatis-config.xml`中开启并配置映射文件或注解。集成Redis缓存时,需添加依赖、配置Redis参数并在映射文件中指定缓存类型。适用于查询为主的场景,减少增删改操作,适合单表操作且表间关联较少的业务。
|
3月前
|
Java Spring
【Spring配置相关】启动类为Current File,如何更改
问题场景:当我们切换类的界面的时候,重新启动的按钮是灰色的,不能使用,并且只有一个Current File 项目,下面介绍两种方法来解决这个问题。
|
3月前
|
Java Spring
【Spring配置】idea编码格式导致注解汉字无法保存
问题一:对于同一个项目,我们在使用idea的过程中,使用汉字注解完后,再打开该项目,汉字变成乱码问题二:本来a项目中,汉字注解调试好了,没有乱码了,但是创建出来的新的项目,写的注解又成乱码了。
|
Java 数据库连接 mybatis
MyBatis-Spring配置简单了解
在基本的 MyBatis 中,session 工厂可以使用 SqlSessionFactoryBuilder 来创建。而在 MyBatis-spring 中,则使用 SqlSessionFactoryBean 来替代。
901 0