近日接到一个需求,要在公司的一个老老老项目(Tomcat + Spring + Hibernate3 )上进行开发。由于这次的需求需要展示不少来源的数据,之前开发配置的独苗苗数据源不够用了,得配置多数据源。
项目之前的数据连接池用的是 ProxoolDataSource ,这个数据连接池我之前没有接触过,也因此踩了坑。先贴一下,之前数据源的配置(applicationContext.xml文件里)是下面这样的,然后把dataSource注入到SessionFactory,SessionFactory注入到HibernateTemplate中:
<bean id="dataSource"
class="org.logicalcobwebs.proxool.ProxoolDataSource"
lazy-init="false">
<property name="driver" value="${jdbc.driverClassName}" />
<property name="driverUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="maximumActiveTime" value="${jdbc.maximumActiveTime}" />
<property name="prototypeCount" value="${jdbc.prototypeCount}" />
<property name="maximumConnectionCount" value="${jdbc.maximumConnectionCount}" />
<property name="minimumConnectionCount" value="${jdbc.minimumConnectionCount}" />
<property name="simultaneousBuildThrottle" value="${jdbc.simultaneousBuildThrottle}" />
<property name="houseKeepingTestSql" value="${jdbc.houseKeepingTestSql}" />
<property name="houseKeepingSleepTime" value="${jdbc.houseKeepingSleepTime}" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<!-- 指定Hibernate的连接方言-->
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</prop>
<!-- 指定是否显示sql语句 -->
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.use_sql_comments">false</prop>
<!--是否使用查询缓存 -->
<prop key="hibernate.cache.use_second_level_cache">false</prop>
<prop key="hibernate.cache.use_query_cache">false</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
<prop key="hibernate.hbm2ddl.auto">false</prop>
<prop key="hibernate.connection.release_mode">after_transaction</prop>
</props>
</property>
<property name="packagesToScan">
<list>
<value>com.XXX</value>
</list>
</property>
</bean>
<!-- 配置模板 -->
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<!-- 配置事务管理 -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
接着,我用了最土的方法去配置多数据源,把上面的4个再创建一份mps版的(冗余,不贴了),接着进行测试。
@Autowired
@Qualifier("hibernateTemplate")
private HibernateTemplate hibernateTemplate;
@Autowired
@Qualifier("mpsHibernateTemplate")
private HibernateTemplate mpsHibernateTemplate;
通过断点确认两个对象注入的是不同的对象,但是发现结果始终是dataSource那个数据库的执行结果,mpsDataSource像是消失了一般。
在网上没搜到相关的情况,就在我打算用原生的jdbc的时候,工位旁的旭哥带着我看起了源码,渐渐找到了答案。可以看到在下图这一步,连接池还是正常的,是mpsDataSource。
问题出在this.dataSource后的getConnection这,执行这的时候是根据alias来获取connection连接。由于在配置数据源的时候,两个数据源都没有指定alias属性,所以alias为null,然后得到的cp是字符串null(这个设计挺独特的...null字符串),通过片段执行发现获取到的connection已经变了,不再是mpsDataSource配置的数据库链接。
至此,问题终于发现了,接下来对症下药即可。
解决方案很多,换一个连接池(druid、c3p0等)可以解决(我试了),不过最后我还是选择在配置文件里加上alias属性,dataSource和mpsDataSource都配上alias就可以了。毕竟老项目,还得想想换个数据源会不会引发更多的bug,就不折腾了。