笔者在实际应用中遇到需要在一个项目工程里,通过不同的DAO操作不同的数据库下的某个数据表,原来使用的方法是,在Spring的配置文件applicationContext.xml里配置两个dataSource,然后配置两个abstractSessionFactory对应这两个dataSource,再配置两个sessionFactory对应这两个abstractSessionFactory,接着配置两个transactionManager管理这两个sessionFactory,总之就是工程需要连接几个数据库,所有关于数据源的配置就得对应配置几套。
当然还需要记着在web.xml里为每个sessionFactory配置对应的openSessionInViewFilter
然后在程序中,通过将对某个数据库操作的DAO统一继承某个基础DAO类,此DAO继承org.springframework.orm.hibernate3.support.HibernateDaoSupport,实现如下方法,参数是 SessionFactory,通过@Resource注解,把某个数据库对应的SessionFactory对象,注入到这个方法中来,然后再这个方法中调 用父类HibernateDaoSupport中的setSessionFactory(SessionFactory sessionFactory)方法把sessionFactory对象传递进去(不重写是因为HibernateDaoSupport的这个方法是final的)。
以上方法配置复杂,并涉及多个配置文件,而且这样的配置方法无法扩展到动态选择一个数据源,比如以下场景:为了保障服务的稳定性,我们配置了一个数据库的代理层,统一管理分发数据库操作,实现读写分离,这样的一个代理层设置了多个ip入口,已保证冗余。那么如何在一个ip不可用时,能自动切换到另一个可用的ip端口呢?
其实Spring本身提供了动态数据源的抽象实现类org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSourc
以本文最初的需求为例,我们来看看通过继承AbstractRoutingDataSourc
首先创建一个枚举类,设置不同的dataSource类别。
接下来创建一个类,来在Context里设置和持有数据源类型,在这个需求里,并发的不同的DAO调用,会根据DAO的不同连接不同的数据库,因此我们通过ThreadLocal来维护这个DataSourceType变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
最后就是实现定制的继承AbstractRoutingDataSourc
接下来就是在applicationContext.xml里配置这么一个数据源来管理两个dataSource。
先配置两个独立的dataSource
然后配置一个dataSource来管理这两个dataSource
其余部分都和正常的配置一个数据源管理无异,完成了配置后,改写我们的基础DAO
这样就完成了多数据源的配置,大家可以按照这个思路稍加变动,应该就可以找出实现动态切换数据源的办法了。