2022年spring+hibernate解决多数据源问 .pdf

上传人:Che****ry 文档编号:27269216 上传时间:2022-07-23 格式:PDF 页数:7 大小:373.64KB
返回 下载 相关 举报
2022年spring+hibernate解决多数据源问 .pdf_第1页
第1页 / 共7页
2022年spring+hibernate解决多数据源问 .pdf_第2页
第2页 / 共7页
点击查看更多>>
资源描述

《2022年spring+hibernate解决多数据源问 .pdf》由会员分享,可在线阅读,更多相关《2022年spring+hibernate解决多数据源问 .pdf(7页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、在我们的项目中遇到这样一个问题:我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。我们以往在spring和 hibernate框架中总是配置一个数据源, 因而 sessionFactory的 dataSource属性总是指向这个数据源并且恒定不变,所有DAO 在使用 sessionFactory的时候都是通过这个数据源访问数据库。但是现在,由于项目的需要,我们的DAO在访问 sessionFactory的时候都不得不在多个数据源中不断切换,问题就出现了:如何让 sessionFactory在执行数据持久化的时候,根据客户的需求能够动态切换不同的数据源?我们能

2、不能在spring 的框架下通过少量修改得到解决?是否有什么设计模式可以利用呢?问题的分析我首先想到在 spring的 applicationContext中配置所有的 dataSource 。这些 dataSource 可能是各种不同类型的, 比如不同的数据库: Oracle 、 SQL Server 、MySQL 等,也可能是不同的数据源:比如apache 提供的mons.dbcp.BasicDataSource、spring 提供的org.springframework.jndi.JndiObjectFactoryBean等。然后 sessionFactory根据客户的每次请求,将dat

3、aSource 属性设置成不同的数据源,以到达切换数据源的目的。但是,我很快发现一个问题:当多用户同时并发访问数据库的时候会出现资源争用的问题。这都是“单例模式”惹的祸。众所周知,我们在使用spring 框架的时候,在 beanFactory 中注册的 bean基本上都是采用单例模式,即spring在启动的时候, 这些 bean 就装载到内存中, 并且每个 bean在整个项目中只存在一个对象。正因为只存在一个对象,对象的所有属性,更准确说是实例变量,表现得就如同是个静态变量(实际上“静态”与“单例”往往是非常相似的两个东西,我们常常用“静态”来实现“单例”)。拿我们的问题来说, session

4、Factory在整个项目中只有一个对象,它的实例变量dataSource 也就只有一个,就如同一个静态变量一般。如果不同的用户都不断地去修改dataSource 的值,必然会出现多用户争用一个变量的问题,对系统产生隐患。通过以上的分析,解决多数据源访问问题的关键,就集中在sessionFactory在执行数据持久化的时候,能够通过某段代码去根据客户的需要动态切换数据源,并解决资源争用的问题。问题的解决(一)采用 Decorator设计模式要解决这个问题,我的思路锁定在了这个dataSource 上了。如果sessionFactory指向的 dataSource 可以根据客户的需求去连接客户所需

5、要的真名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 7 页 - - - - - - - - - 正的数据源, 即提供动态切换数据源的功能,那么问题就解决了。 那么我们怎么做呢?去修改那些我们要使用的dataSource 源码吗?这显然不是一个好的方案,我们希望我们的修改与原dataSource 代码是分离的。根据以上的分析,使用 GoF设计模式中的 Decorator 模式(装饰者模式) 应当是我们可以选择的最佳方案。什么是 “Decorator 模式” ?简单点儿说就

6、是当我们需要修改原有的功能,但我们又不愿直接去修改原有的代码时,设计一个Decorator 套在原有代码外面。当我们使用Decorator的时候与原类完全一样,当Decorator 的某些功能却已经修改为了我们需要修改的功能。Decorator 模式的结构如图。我们本来需要修改图中所有具体的Component类的一些功能,但却并不是去直接修改它们的代码,而是在它们的外面增加一个Decorator 。Decorator 与具体的Component类都是继承的 AbstractComponent ,因此它长得和具体的Component类一样,也就是说我们在使用Decorator 的时候就如同在使用

7、ConcreteComponentA或者 ConcreteComponentB一样,甚至那些使用ConcreteComponentA或者 ConcreteComponentB的客户程序都不知道它们用的类已经改为了 Decorator ,但是 Decorator 已经对具体的 Component类的部分方法进行了修改,执行这些方法的结果已经不同了。(二)设计 MultiDataSource类现在回到我们的问题, 我们需要对 dataSource 的功能进行变更, 但又不希望修改 dataSource 中的任何代码。我这里指的dataSource 是所有实现javax.sql.DataSource

8、接口的类,我们常用的包括apache 提供的mons.dbcp.BasicDataSource、spring 提供的org.springframework.jndi.JndiObjectFactoryBean等,这些类我们不可能修改它们本身,更不可能对它们一个个地修改以实现动态分配数据源的功能,同时,我们又希望使用 dataSource 的 sessionFactory根本就感觉不到这样的变化。Decorator 模式就正是解决这个问题的设计模式。首先写一个 Decorator 类,我取名叫 MultiDataSource ,通过它来动态切换数据源。 同时在配置文件中将sessionFacto

9、ry的 dataSource 属性由原来的某个具体的 dataSource 改为 MultiDataSource 。如图:名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 2 页,共 7 页 - - - - - - - - - 对比原 Decorator 模式,AbstractComponent 是一个抽象类,但在这里我们可以将这个抽象类用接口来代替,即DataSource 接口,而 ConcreteComponent 就是那些 DataSource 的实现类,如 BasicDataS

10、ource 、JndiObjectFactoryBean等。MultiDataSource封装了具体的 dataSource ,并实现了数据源动态切换:java 代码1.public class MultiDataSource implements DataSource 2. private DataSource dataSource = null; 3.public MultiDataSource(DataSource dataSource) 4. this.dataSource = dataSource; 5. 6. /* (non-Javadoc) 7. * see javax.sql.

11、DataSource#getConnection() 8. */ 9. public Connection getConnection() throws SQLException 10. return getDataSource().getConnection(); 11. 12. /其它 DataSource 接口应当实现的方法13.14. public DataSource getDataSource() 15. return this.dataSource; 16. 17. 18. public void setDataSource(DataSource dataSource) 19.

12、this.dataSource = dataSource; 20. 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 3 页,共 7 页 - - - - - - - - - 21. 客户在发出请求的时候, 将 dataSourceName放到 request 中, 然后把 request中的数据源名通过调用new MultiDataSource(dataSource)时可以告诉MultiDataSource客户需要的数据源,就可以实现动态切换数据源了。但细心的朋友会发现这在单例的情况下

13、就是问题的,因为MultiDataSource在系统中只有一个对象,它的实例变量 dataSource也只有一个,就如同一个静态变量一般。正因为如此,单例模式让许多设计模式都不得不需要更改,这将在我的“单例”更改了我们的设计模式中详细讨论。那么,我们在单例模式下如何设计呢?( 三)单例模式下的 MultiDataSource 在单例模式下,由于我们在每次调用MultiDataSource的方法的时候,dataSource 都可能是不同的,所以我们不能将dataSource 放在实例变量dataSource 中,最简单的方式就是在方法getDataSource() 中增加参数,告诉MultiDa

14、taSource我到底调用的是哪个dataSource :java 代码1.public DataSource getDataSource(String dataSourceName) 2. log.debug(dataSourceName:+dataSourceName); 3. try 4. if(dataSourceName=null|dataSourceName.equals() 5. return this.dataSource; 6. 7. return (DataSource)this.applicationContext.getBean(dataSourceName); 8.

15、catch(NoSuchBeanDefinitionException ex) 9. throw new DaoException(There is not the dataSource 10. 11. 值得一提的是,我需要的数据源已经都在spring 的配置文件中注册,dataSourceName就是其对应的id。xml 代码1. 3. 4. oracle.jdbc.driver.OracleDrivervalue 5. property 6. . 7.bean 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 -

16、 - - - - - - 第 4 页,共 7 页 - - - - - - - - - 8. 10. 11. oracle.jdbc.driver.OracleDrivervalue 12. property 13. . 14.bean 为了得到 spring 的 ApplicationContext, MultiDataSource类必须实现接口org.springframework.context.ApplicationContextAware,并且实现方法:java 代码1.private ApplicationContext applicationContext = null; 2.pu

17、blic void setApplicationContext(ApplicationContext applicationContext) throws BeansException 3. this.applicationContext = applicationContext; 4. 如此这样,我就可以通过this. applicationContext.getBean(dataSourceName)得到 dataSource了。( 四)通过线程传递 dataSourceName 查看以上设计, MultiDataSource依然无法运行,因为用户在发出请求时,他需要连接什么数据库, 其数

18、据源名是放在request 中的,要将 request 中的数据源名传给 MultiDataSource ,需要经过 BUS 和 DAO ,也就是说为了把数据源名传给 MultiDataSource , BUS 和 DAO 的所有方法都要增加dataSourceName的参数,这是我们不愿看到的。写一个类,通过线程的方式跳过BUS和 DAO 直接传递给MultiDataSource是一个不错的设计:java 代码1.public class SpObserver 2. private static ThreadLocal local = new ThreadLocal(); 名师资料总结 -

19、- -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 5 页,共 7 页 - - - - - - - - - 3. public static void putSp(String sp) 4. local.set(sp); 5. 6. public static String getSp() 7. return (String)local.get(); 8. 9. 做一个 filter,每次客户发出请求的时候就调用SpObserver.petSp(dataSourceName) ,将request中的dat

20、aSourceName传递给SpObserver对象。最后修改 MultiDataSource的方法 getDataSource() :java 代码1.public DataSource getDataSource() 2. String sp = SpObserver.getSp(); 3. return getDataSource(sp); 4. 完整的 MultiDataSource代码在附件中。( 五)动态添加数据源通过以上方案,我们解决了动态分配数据源的问题,但你可能提出疑问:方案中的数据源都是配置在spring 的 ApplicationContext中, 如果我在程序运行过程中

21、动态添加数据源怎么办?这确实是一个问题,而且在我们的项目中也确实遇到。 spring 的 ApplicationContext是在项目启动的时候加载的。加载以后,我们如何动态地加载新的bean 到 ApplicationContext中呢?我想到如果用spring 自己的方法解决这个问题就好了。 所幸的是,在查看 spring 的源代码后,我找到了这样的代码,编写了DynamicLoadBean类,只要调用 loadBean() 方法,就可以将某个或某几个配置文件中的bean 加载到ApplicationContext中(见附件)。不通过配置文件直接加载对象,在spring的源码中也有,感兴趣

22、的朋友可以自己研究。( 六)在 spring 中配置在完成了所有这些设计以后, 我最后再唠叨一句。 我们应当在 spring中做如下配置:xml 代码1.bean 2. 3. 4. 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 6 页,共 7 页 - - - - - - - - - 5. property 6. bean 7. 8. 9. 10. property 11. . 12. bean 其中 dataSource 属性实际上更准确地说应当是defaultDataSource

23、,即spring 启动时以及在客户没有指定数据源时应当指定的默认数据源。该方案的优势以上方案与其它方案相比,它有哪些优势呢?首先,这个方案完全是在spring 的框架下解决的, 数据源依然配置在spring的配置文件中, sessionFactory依然去配置它的 dataSource 属性,它甚至都不知道 dataSource 的改变。 唯一不同的是在真正的dataSource 与 sessionFactory之间增加了一个 MultiDataSource 。其次,实现简单,易于维护。这个方案虽然我说了这么多东西,其实都是分析,真正需要我们写的代码就只有MultiDataSource 、Sp

24、Observer 两个类。MultiDataSource类真正要写的只有getDataSource() 和 getDataSource(sp) 两个方法,而 SpObserver 类更简单了。实现越简单,出错的可能就越小,维护性就越高。最后,这个方案可以使单数据源与多数据源兼容。这个方案完全不影响BUS和 DAO 的编写。如果我们的项目在开始之初是单数据源的情况下开发,随着项目的进行,需要变更为多数据源,则只需要修改spring 配置,并少量修改MVC 层以便在请求中写入需要的数据源名,变更就完成了。 如果我们的项目希望改回单数据源,则只需要简单修改配置文件。这样,为我们的项目将增加更多的弹性。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 7 页,共 7 页 - - - - - - - - -

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 教育专区 > 高考资料

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁