Spring MVC配置多个数据源可能遇到的坑

由于业务需要连接多个数据源,在进行配置的过程中遇到了一些坑,在此做一下记录和分享。
jdbc.properties文件中多个数据源的基本信息:

# 数据源1
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/user?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=GMT%2B8
jdbc.username=root
jdbc.password=123456

#数据源2
jdbc.driver1=com.mysql.cj.jdbc.Driver
jdbc.url1=jdbc:mysql://localhost:4444/newsclient?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=GMT%2B8
jdbc.username1=root
jdbc.password1=123456

在applicationContext.xml文件中对数据源进行配置:

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!-- 基本属性 url、user、password -->
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <bean id="dataSource1" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!-- 基本属性 url、user、password -->
        <property name="driverClassName" value="${jdbc.driver1}"/>
        <property name="url" value="${jdbc.url1}"/>
        <property name="username" value="${jdbc.username1}"/>
        <property name="password" value="${jdbc.password1}"/>
    </bean>

在applicationContext.xml文件中配置mybatisSqlSessionFactoryBean:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:mybatis.xml"/>
        <property name="mapperLocations" value="classpath*:com/flh/dao/xml/*Mapper.xml"/>
</bean>
<bean id="sqlSessionFactory1" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource1" />
        <property name="configLocation" value="classpath:mybatis.xml"/>
        <property name="mapperLocations" value="classpath*:com/flh/dao1/xml/*Mapper.xml"/>
</bean>

应该注意两个sqlSessionFactory的mapperLocations应该是不一样的;

在applicationContext.xml文件中配置SqlSessionTemplate:

<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
<bean id="sqlSessionTemplate1" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory1" />
</bean>

在applicationContext.xml文件中配置mybatis mapper接口,扫描所有dao:

<bean id = "mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.flh.dao"/>
        <property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"/>
</bean>
<bean id = "mapperScannerConfigurer1" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.flh.dao1"/>
        <property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate1"/>
</bean>

应该注意两者的basePackage对应的value要不一致,否则可能会造成 本来去数据源2获取数据,但是真实的请求是从数据源1中获取数据,报错,提示数据源1中不存在某表。

如果是按照以上的配置的,应该是可以成功的。

遇到的问题:

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)错误
具体报错信息:

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.study.server.mapper.UserMapper.insert
    at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:227)
    at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:49)
    at org.apache.ibatis.binding.MapperProxy.cachedMapperMethod(MapperProxy.java:65)
    at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:58)
    at com.sun.proxy.$Proxy88.insert(Unknown Source)

分析

public boolean hasStatement(String statementName, boolean validateIncompleteStatements) {
    if (validateIncompleteStatements) {
      buildAllStatements();
    }
    return mappedStatements.containsKey(statementName);
}

可以看出有2个会发生该异常的情况:
mappedStatements为{} (跟踪debug发现,我出现这里为空)
containsKey(statementName),没有找到
mappedStatements为空的原因是由于在spring容器启动时,会解析spring配置文件,这时将去加载资源文件,解析并以key,value的形式缓存在mappedStatements中。而在实际情况下,发现打包时*Mapper.xml并没有自动复制到class输出目录的mapper类包下。从而导致mappedStatements为空。

网上总结的一般原因

Mapper interface和xml文件的定义对应不上,需要检查包名,namespace,函数名称等能否对应上。
按以下步骤一一执行:
1、检查xml文件所在的package名称是否和interface对应的package名称一一对应
2、检查xml文件的namespace是否和xml文件的package名称一一对应
3、检查函数名称能否对应上
4、去掉xml文件中的中文注释
5、随意在xml文件中加一个空格或者空行然后保存
6、路径问题

项目中的解决方法

在使用IDEA开发时,如果打包时*Mapper.xml没有自动复制到class输出目录的mapper类包下,则需要在pom文件中添加mybatis加载配置文件的配置!
如下:

<build>
  <resources>
    <resource>
        <directory>src/main/java</directory>
      <includes>
        <include>**/*.xml</include>
      </includes>
    </resource>
    <resource>
      <directory>src/main/resources</directory>
    </resource>
  </resources>
</build>

通过在pom文件中添加mybatis加载配置文件,完美解决遇到的问题了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容