问题描述
在使用Spring整合Mybatis时 配置C3P0连接池时报Could not load driverClass ${jdbc.driver} 错误 但可以正常查询到数据 如果将表达式修改为具体值则不会报错
原因分析
在整合mybatis时配置了MapperScannerConfigurer 而MapperScannerConfigure需要注入SqlSessionFactory工厂 而SqlSessionFactory工厂需要注入数据源 从而引发了一系列的关联 然而问题则出现在MapperScannerConfigurer与数据源的执行顺序上
MapperScannerConfigurer会先于数据源执行 因此在MapperScannerConfigurer执行之后就把表达式${jdbc.driver}当作字符串执行
又因为c3p0有默认的重连机制 确保数据库恢复后能够可以继续连接 因此当driver刚开始注入失败时会继续尝试重新连接 默认30次
解决方案
解决方案有两个
方案1
注入mybatis的MapperScannerConfigurer时 给sqlSessionFactoryBeanName属性注入值
注意 值为String类型(使用value赋值) 同时要确保IOC容器中已经存在了名称为sqlSessionFactroy的bean
示例
<context:property-placeholder location="classpath:database.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="sqlSessionFactroy" 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="sqlSessionFactoryBeanName" value="sqlSessionFactroy"/>
<property name="basePackage" value="com.kuang.dao"/>
</bean>
方案2
让spring的ioc自动注入 我们不在手动关联sqlSessionFactoryBean的注入
即 在注入myatis的MapperScannerConfigurer时 不指定sqlSessionFactoryBeanName
注意: 在配置SqlSessionFactoryBean会话工厂bean时 id属性名必须为sqlSessionFactory 否则Spring无法自动关联
示例
<?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"
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">
<context:property-placeholder location="classpath:database.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="sqlSessionFactroy" 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">
<!--Spring自动注入sqlSessionFactoryBean 这里不在手动关联 -->
<!--<property name="sqlSessionFactoryBeanName" value="sqlSessionFactroy"/>-->
<property name="basePackage" value="com.kuang.dao"/>
</bean>
</beans>
方案3(未测试)
通过c3p0的配置文件自行配置
即 自定义c3p0-config.xml或c3p0-config.properties文件
然后通过配置文件关联相关的数据库连接信息
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!--<default-config>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/db_demo
</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="checkoutTimeout">30000</property>
<property name="idleConnectionTestPeriod">30</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">200</property>
</default-config>-->
</c3p0-config>