摘要
近期由于项目使用mybatis出现了数据源阻塞,导致应用程序假死,服务超时引发严重后果,故此下定决心重新梳理一下spring+mybatis+c3p0整合问题,主要分为:配置、源码(通过一次数据库操作分析)、myabatis缓存、问题总结
spring + mybatis + c3p0 整合(源码分析)
配置相关
<!-- 自动扫描的包名 -->
<context:component-scan base-package="com.company"/>
<!-- 启用注解 -->
<context:annotation-config />
<!-- 数据源配置(这里由于使用自定义数据源封装) -->
<bean id="dataSource" class="com.company.support.CompanyPooledDataSource" destroy-method="close">
<property name="platId" value="platId(业务系统id)"/>
<property name="databaseName" value="dbName"/>
</bean>
<!-- 常规可以参考 如下 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="DriverClass" value="com.mchange.v2.c3p0.ComboPooledDataSource"></property>
<property name="jdbcUrl" value="jdbc:mysql:///books"></property>
<property name="user" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!-- mabatis SqlSessionFactory 创建Configuration -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- Mapper扫描 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.company.business.mapper" />
<property name="sqlSessionFactory" ref="dataSource"/>
</bean>
<!-- 事务配置 使用注解形式-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref ="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
自定义数据源类部分源码,核心还是ComboPooledDataSource,只是做了一些业务需要封装;c3p0核心参数在WrapperConnectionPoolDataSourceBase类
public CompanyPooledDataSource() {
this.init();
}
private void init() {
try {
# 核心参数配置
this.comboPooledDataSource = new ComboPooledDataSource();
this.setInitialPoolSize(3);#连接池初始化时创建的连接数,default : 3
this.setMinPoolSize(3);#连接池保持的最小连接数,default : 3
this.setMaxPoolSize(30);#连接池中拥有的最大连接数,如果获得新连接时会使连接总数超过这个值则不会再获取新连接,而是等待其他连接释放
this.setMaxIdleTime(1800);#连接的最大空闲时间,如果超过这个时间,某个数据库连接还没有被使用,则会断开掉这个连接。如果为0,则永远不会断开连接,即回收此连接。default : 0 单位 s
this.setAcquireIncrement(5); #连接池在无空闲连接可用时一次性创建的新数据库连接数
this.setMaxStatements(0);#连接池为数据源缓存的PreparedStatement的总数。由于PreparedStatement属于单个Connection,所以这个数量应该根据应用中平均连接数乘以每个连接的平均PreparedStatement来计算。同时maxStatementsPerConnection的配置无效。default : 0(不建议使用)
this.setIdleConnectionTestPeriod(120);#每120秒检查所有连接池中的空闲连接
this.setAcquireRetryAttempts(30);#连接池在获得新连接失败时重试的次数,如果小于等于0则无限重试直至连接获得成功。
...
} catch (Exception var2) {
var2.printStackTrace();
throw new IllegalArgumentException("初始化数据库连接池异常" + var2.getLocalizedMessage());
}
}