MapperScannerConfigurer 配置出错造成没有读取 db.properties 文件中的数据库连接参数
MyBatis-Spring 实现 MyBatis 和 Spring 框架集成。
问题现象
在配置中碰到不能加载 MySQL JDBC 驱动的问题,报错如下(部分截取):
09:59:06.595 [C3P0PooledConnectionPoolManager[identityToken->z8kfltb71qnbl7e1cco0kz|23833818]-HelperThread-#2] WARN c.m.v2.c3p0.DriverManagerDataSource - Could not load driverClass ${jdbc.driverClass}
java.lang.ClassNotFoundException: ${jdbc.driverClass}
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1332)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1144)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:534)
at java.base/java.lang.Class.forName(Class.java:513)
at com.mchange.v2.c3p0.DriverManagerDataSource.loadDriverClass(DriverManagerDataSource.java:129)
at com.mchange.v2.c3p0.DriverManagerDataSource.ensureIfPossibleDriverClassLoaded(DriverManagerDataSource.java:108)
at com.mchange.v2.c3p0.DriverManagerDataSource.getConnection(DriverManagerDataSource.java:157)
at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:167)
at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:153)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.acquireResource(C3P0PooledConnectionPool.java:499)
at com.mchange.v2.resourcepool.BasicResourcePool.doAcquire(BasicResourcePool.java:1112)
at com.mchange.v2.resourcepool.BasicResourcePool.doAcquireAndDecrementPendingAcquiresWithinLockOnSuccess(BasicResourcePool.java:1099)
at com.mchange.v2.resourcepool.BasicResourcePool.access$700(BasicResourcePool.java:9)
at com.mchange.v2.resourcepool.BasicResourcePool$ScatteredAcquireTask.run(BasicResourcePool.java:1846)
at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:696)
Caused by: java.sql.SQLException: No suitable driver
at java.sql/java.sql.DriverManager.getDriver(DriverManager.java:300)
at com.mchange.v2.c3p0.DriverManagerDataSource.driver(DriverManagerDataSource.java:273)
at com.mchange.v2.c3p0.DriverManagerDataSource.getConnection(DriverManagerDataSource.java:159)
at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:167)
at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:153)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.acquireResource(C3P0PooledConnectionPool.java:499)
at com.mchange.v2.resourcepool.BasicResourcePool.doAcquire(BasicResourcePool.java:1112)
at com.mchange.v2.resourcepool.BasicResourcePool.doAcquireAndDecrementPendingAcquiresWithinLockOnSuccess(BasicResourcePool.java:1099)
at com.mchange.v2.resourcepool.BasicResourcePool.access$700(BasicResourcePool.java:9)
at com.mchange.v2.resourcepool.BasicResourcePool$ScatteredAcquireTask.run(BasicResourcePool.java:1846)
at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:696)
环境配置
SSM 框架集成的主要配置如下:
依赖:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.17</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>3.0.4</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.10.1</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>9.1.0</version>
<scope>runtime</scope>
</dependency>
db.properties:
jdbc.driverClass=com.mysql.cj.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql://127.0.0.1/java
jdbc.user=root
jdbc.password=root
spring.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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="cn.oraenv.javaweb.dao"/>
<aop:aspectj-autoproxy/>
<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven/>
<bean name="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactory" ref="sqlSessionFactoryBean"/>
<property name="basePackage" value="cn.oraenv.javaweb.dao"/>
</bean>
</beans>
问题解析
根据异常报错信息可以看出 JDBC 驱动的类全路经名没有替换为 db.properties 文件中的值,从而造成不能加载 MySQL 的 JDBC 驱动。
经过排查后发现是 MapperScannerConfigurer 的配置出错,使用 sqlSessionFactory 属性名以 ref 方式进行注入,会造成 org.mybatis.spring.SqlSessionFactoryBean 提前初始化,但是此时 ${jdbc.driverClass} 等参数的替换还未开始,无法读取到正确的数据库连接配置。
官方文档中对 MapperScannerConfigurer 的配置方法描述如下:

下面总结 MapperScannerConfigurer 的配置方法:
- 如果 Spring 上下文中只有一个 sqlSessionFactory,那么不用手动注入
sqlSessionFactory属性; - 如果 Spring 上下文中有多个 sqlSessionFactory, 那么使用
sqlSessionFactoryBeanName属性以 value 方式注入字符串的 Bean 名称。
修改后的配置段如下:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean"/>
<property name="basePackage" value="cn.oraenv.javaweb.dao"/>
</bean>
至此数据库连接正常。
刚开始配置的时候以为加了这项配置也不要紧,不以为然,谁成想出现这样的错误,最后通过排查和查资料,定位解决了这个问题。
问题还涉及 Bean 的生命周期和后处理的相关知识,现在水平还不到,放到以后学习。
浙公网安备 33010602011771号