在前面我写了《
如何在spring框架中解决多数据源的问题》,通过设计模式中的Decorator模式在spring框架中解决多数据源的问题,得到了许多网友的关注。在与网友探讨该问题的过程中,我发现我的方案并不完善,它只解决了一部分问题。
总结多数据源的问题,其实它需要分为以下三种情况:各个数据源的数据结构不同、各个数据源的数据结构相同、各个数据源的数据结构部分相同又有部分不同。对于第二种情况,各个数据源的数据结构相同,我们使用一个sessionFactory,而在sessionFactory中通过MultiDataSource来动态切换数据源,应当是一个不错的方案,既解决了多个sessionFactory对相同的值对象重复装载对内存的浪费,又使数据源的切换对客户程序透明,简化了代码的实现和对客户程序的影响。但是,对于第一种情况,各个数据源的数据结构不同,运用这样的方案存在潜在风险。
对于各个数据源的数据结构不同的情况,使用一个sessionFactory而在这个sessionFactory中动态切换数据源,可能造成数据访问的张冠李戴。譬如,数据源A有表T而数据源B没有,可能造成客户程序在访问表T的时候却尝试去连接数据源B,因为客户程序访问哪个数据源是在程序运行期间由客户程序决定的,因此这样的错误是很难发现的。也许客户程序的一个不经意的错误就可能造成错误。解决这个问题的方法有两个:一是严格要求客户程序不要写错,这当然是可以做到的,但作为框架设计者,另一个解决方法是在框架中就避免出现这样的情况。因此我祭出了MultiSessionFactory的方案来解决各个数据源的数据结构不同的多数据源问题。
问题的分析
与MultiDataSource的方案一样,MultiSessionFactory同样是在spring框架下调用ApplicationContext的getBean()方法而不会另外创建beanFacoty,也同样使用Decorator模式来处理切换的问题。MultiSessionFactory的对象关系如图:
在该方案中,SessionFactory就是Hibernate的org.hibernate.SessionFactory接口,Decorator就是MultiSessionFactory,SessionFactory1和SessionFactory2往往是spring的org.springframework.orm.hibernate3.LocalSessionFactoryBean。细心的朋友可能会注意,实际上LocalSessionFactoryBean并不是SessionFactory的实现,这个方案是否有问题呢?这个问题其实也一直困扰了我好久,最后我发现,我们通过ApplicationContext的getBean()得到一个LocalSessionFactoryBean的时候其实并不是真正地得到了它,而是得到了一个SessionFactory,因为spring为LocalSessionFactoryBean重写了getObject(),使其返回的是SessionFactory。一个简单的明证就是,HibernateDaoSupport的sessionFactory属性的类型是SessionFactory,而我们在spring配置的时候注入的却是LocalSessionFactoryBean。
方案的实现
在整个这个方案中,我们需要实现的只有MultiSessionFactory类和我们可爱的Spserver,总共就两个类,然后呢就是一些spring的配置,就完成了。
MultiSessionFactory实现了SessionFactory,同时为了得到AplicationContext而实现了ApplicationContextAware。MultiSessionFactory的代码如下:
java 代码
- publicclassMultiSessionFactoryimplementsSessionFactory,ApplicationContextAware{
- privatestaticfinallongserialVersionUID=2064557324203496378L;
- privatestaticfinalLoglog=LogFactory.getLog(MultiSessionFactory.class);
- privateApplicationContextapplicationContext=null;
- privateSessionFactorysessionFactory=null;
- publicApplicationContextgetApplicationContext(){
- returnapplicationContext;
- }
- publicvoidsetApplicationContext(ApplicationContextapplicationContext){
- this.applicationContext=applicationContext;
- }
- publicSessionFactorygetSessionFactory(StringsessionFactoryName){
- log.debug("sessionFactoryName:"+sessionFactoryName);
- try{
- if(sessionFactoryName==null||sessionFactoryName.equals("")){
- returnsessionFactory;
- }
- return(SessionFactory)this.getApplicationContext().getBean(sessionFactoryName);
- }catch(NoSuchBeanDefinitionExceptionex){
- thrownewDaoException("ThereisnotthesessionFactory
- }
- }
-
- publicSessionFactorygetSessionFactory(){
- StringsessionFactoryName=SpObserver.getSp();
- returngetSessionFactory(sessionFactoryName);
- }
-
- publicvoidsetSessionFactory(SessionFactorysessionFactory){
- this.sessionFactory=sessionFactory;
- }
-
- //SessionFactory接口需要实现的方法
-
- ......
-
- }
MultiSessionFactory的完整代码见我提供的附件。setSessionFactory()实际上是设定的默认sessionFactory,它在spring装载的时候调用,其对应的数据源应当是主数据源,即项目初始化中需要读取初始化数据的数据源。在任何多数据源项目中,都应当有一个存放初始化数据、系统维护数据、用户权限数据的数据源,这就是主数据源。因此MultiSessionFactory的配置应当这样写:
xml 代码
- <beanid="sessionFactory"class="com.htxx.service.dao.MultiSessionFactory">
- <propertyname="sessionFactory"><refbean="hostSessionFactory"/>property>
- >
SpServer的写法与《如何在spring框架中解决多数据源的问题》中的一样,我就不再累赘了。
另外,在spring配置中配置多个数据源,每个数据源对应一个sessionFactory,这个对应的sessionFactory中的值对象应当是该数据源的值对象。客户程序在执行数据访问前,通过调用SpServer的putSp()方法,告诉MultiSessionFactory需要切换到哪个sessionFactory,然后执行数据访问。这样,不同数据源的值对象通过放在不同的sessionFactory中,避免了张冠李戴的情况。具体的示例见附件的MultiSessionFactoryTest。
另外的方案
也许有些朋友对以上方案还不满意,因为在执行数据访问前毕竟还要多做一步指定sessionFactory的工作。实际上,对于各个数据源的数据结构不同的项目,一个值对象应当使用哪个数据源有一个非常确定的对应关系。如果通过配置文件将值对象与它的sessionFactory对应起来,那么我们在执行数据访问的时候传递的是哪个值对象,MultiSessionFactory马上就可以去找到对应的sessionFactory。这个方案你可以通过AOP来制作一个拦截器拦截所有诸如save()、delete()、get()、load()等方法来实现,也可以扩展HibernateDaoSupport来实现。这样的方案使客户程序甚至都不用知道他是在操作的一个多数据源系统。当然,这个方案感兴趣的朋友可以自己去实现。
另外,在这个方案中的核心是运用Decorator设计模式来解决切换sessionFactory的目的,即MultiSessionFactory的实现。至于通过什么方式来通知MultiSessionFactory应当切换到哪个SessionFactory,可以根据不同项目的情况自由选择。我在这里给大家提供了通过SpOberver和建立值对象与sessionFactory关系的配置文件这两个方案,你也可以有自己的方案解决。
第三种情况的解决方案
前面我已经给出了第一种和第二种情况的解决方案:各个数据源的数据结构不同的情况用MultiSessionFactory解决;各个数据源的数据结构相同的情况用MultiDataSource解决。那么第三种情况,各个数据源的数据结构部分相同又有部分不同,又应当如何解决呢?当然是将MultiSessionFactory和MultiDataSource结合起来解决。对于数据结构不同的部分,其分别创建各自的sessionFactory然后通过MultiSessionFactory来切换,而对于数据结构相同的部分,建立共同的sessionFactory和多个不同的dataSource然后通过MultiDataSource来切换就可以了。
还有的朋友问到这样的方案其事务处理和二级缓存的情况。这个方案是在spring框架下的解决方案,其事务处理的能力也是由spring的能力来决定的。目前spring要处理跨数据库的事务处理是通过JTA来实现的,这种方式在该方案中同样可以实现,朋友们可以试一试。另外,本方案能使用二级缓存吗?当然可以。对于MultiSessionFactory当然没有任何问题,它通过不同的sessionFactory分离开了不同的数据源和值对象,我们可以毫无顾忌地使用。对于MultiDataSource来说,就有点问题了。MultiDataSource使多个数据源使用共同的sessionFactory,因此它仿佛就是将多个数据源在逻辑上合并为一个数据源。正因为如此,我们需要保证对于同一个表在所有数据源中都要主键唯一。什么意思呢?数据源A和数据源B都有表T,如果数据源A中的表T拥有ID为001的一条数据,那么在数据源B的表T中就不能有ID为001的记录。如果你总是通过MultiDataSource来执行表的插入操作,并且使用uuid.hex生成主键,这当然不会有问题。但如果你有通过其它方式插入表的操作,你应当保证这样的唯一性。另外,对于查询的操作,缓存中存放的既可能是数据源A的数据,也可能是数据源B的数据,因此你应当对数据有一个规划。对于表T的数据,哪些应当插入到数据源A中,哪些应当插入到B中,应当有一个定义。假如是通过不同单位来决定插入哪个数据源,那么在查询数据源A的表T是,应当增加条件只查询数据源A应当有的单位而排除调其它单位。如此这样,你只要注意到这两个问题,你就可以放心大胆地使用二级缓存。
分享到:
相关推荐
### 如何在Spring框架中解决多数据源的问题 #### 问题背景及挑战 在实际的软件开发过程中,尤其是在企业级应用开发中,经常会遇到需要同时处理多个数据源的情况。例如,一个应用程序可能需要同时访问Oracle数据库...
在多数据源的配置中,需要有一种机制来实现数据源的动态切换。这通常涉及到根据业务逻辑条件选择不同的数据源来执行数据库操作。在应用程序运行过程中,可以根据需要动态地切换数据源,这可能涉及到会话工厂中数据库...
首先,这个方案完全是在spring的框架下解决的,数据源依然配置在spring的配置文件中,sessionFactory依然去配置它的dataSource属性,它甚至都不知道dataSource的改变。 其次,实现简单,易于维护。这个方案虽然我说...
在SSH框架中,多数据源配置可以通过使用Spring框架的数据源配置来实现。Spring框架提供了多种数据源配置方式,包括基于XML的配置和基于Annotation的配置。在这个例子中,我们使用基于XML的配置方式来实现多数据源...
6. **事务管理**:在多数据源环境下,事务管理变得复杂。Spring的PlatformTransactionManager接口可以扩展以支持多数据源事务。我们可以使用`AbstractRoutingDataSource`作为基础,创建一个动态路由数据源,根据业务...
在多数据源配置中,Spring能够帮助管理不同的数据源,通过配置bean来切换和控制数据源的使用。 **SpringMVC** 是Spring框架的一部分,专为Web开发设计。它简化了模型-视图-控制器(Model-View-Controller,MVC)的...
Spring Boot结合JPA(Java Persistence API)和JdbcTemplate,为开发者提供了灵活且强大的多数据源配置能力。本示例将详细介绍如何在Spring Boot项目中实现这样的配置,以支持不同类型的数据库。 首先,我们要理解...
在多数据源的场景下,Hibernate提供了灵活的数据源配置,可以在同一个应用中管理多个数据库连接。这通常通过定义不同的SessionFactory配置和DataSource实例来实现。 **MyBatis** 则是一个轻量级的ORM框架,它比...
5. **事务管理**:在多数据源环境下,事务管理也需要特别注意。Spring的PlatformTransactionManager应配置为DataSourceTransactionManager,并且需要确保它知道如何处理多个数据源。在事务开始时,事务管理器会根据...
在多数据源场景下,Hibernate可以配置为连接不同的数据库,使得应用可以根据业务需求灵活切换数据源。 **多数据源** 是指在一个应用中管理多个独立的数据库连接。在本项目中,数据源被配置为Hibernate和Datastore,...
但在多数据源场景下,我们不能只依赖这些基本配置。 1. **配置多数据源** - 创建两个或更多的数据源配置类,每个数据源对应一个配置类,例如:`PrimaryDataSourceConfig` 和 `SecondaryDataSourceConfig`。 - 在...
在Spring框架中,多数据源的支持使得应用可以同时连接并操作多个不同的数据库,这在分布式系统、微服务架构或者需要处理多种数据类型的场景下非常有用。"Spring动态切换多数据源Demo"是一个示例项目,它展示了如何在...
在多数据源环境中,每个数据源需要一个单独的SessionFactory。我们可以为每个数据源创建一个SessionFactory配置,并指定相应的DataSource,实体扫描路径,以及其他的Hibernate配置参数。 在"压缩包子文件的文件名称...
如何在spring框架中解决多数据源的问题源码
在多数据源切换实例中,我们假设已经部署了两个或更多的Oracle数据库实例,每个实例可能存储不同类型或者不同业务领域内的数据。 实现多数据源切换的关键步骤如下: 1. **配置数据源**:在Spring的配置文件中,...
"工具"可能是指像Druid、HikariCP这样的数据库连接池,它们在多数据源配置中起着至关重要的作用,提供高效且稳定的数据库连接管理。 至于压缩包文件名称 "JX_VIDEO_SYNCHRONIZATION",它看起来与视频同步相关,但...
在多数据源场景下,Mybatis可以通过SqlSessionFactoryBuilder创建多个SqlSessionFactory实例,每个实例对应一个数据源,从而实现数据源的隔离。 实现多数据源通常有以下步骤: 1. **配置数据源**:首先,你需要...
在本项目中,我们将探讨如何利用MyBatis与Spring框架实现动态切换数据源的功能。首先,我们需要理解MyBatis和Spring的基本概念以及它们如何协同工作。 MyBatis是一个优秀的持久层框架,它简化了Java与数据库之间的...
- 注意事务管理的配置,确保在多数据源环境下事务的一致性。 8. **应用场景**: - 分布式系统中,不同的服务可能需要连接不同的数据库。 - 高并发场景下,可以通过数据源分片来分散压力。 - 读写分离,主库负责...
1. 配置事务管理器:在多数据源的情况下,需要配置两个PlatformTransactionManager,对应每个数据源,并在需要的地方进行指定。 2. 数据源切换:在运行时,确保根据业务需求正确切换数据源,避免出现数据不一致的...