由于业务需要连接多个数据源,在进行配置的过程中遇到了一些坑,在此做一下记录和分享。
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加载配置文件,完美解决遇到的问题了。