`

ssh架构按照需求动态切换不同的数据库

阅读更多

 

<!--[if !supportLists]-->1、    问题: 如何 <!--[endif]-->根据用户的选择,使用不同的数据源?

<!--[if !supportLists]-->2、    <!--[endif]-->解决思路:将sessionFactory的属性dataSource设置成不同的数据源,以达到切换数据源的目的。

<!--[if !supportLists]-->3、   <!--[endif]-->问题产生:因为整个项目用的几乎都是单例模式,当多个用户并发访问数据库的时候,会产生资源争夺的问题。即项目启动时候,所有的bean都被装载到内存,并且每个bean都只有一个对象。正因为只有一个对象,所有的对象属性就如同静态变量(静态变量跟单例很相似,常用静态来实现单例)。整个项目系统的dataSource只有一个,如果很多用户不断的去改变dataSource的值,那必然会出现资源的掠夺问题,造成系统隐患。

<!--[if !supportLists]-->4、 <!--[endif]-->多资源共享解决思路:同一资源被抢夺的时候,通常有两种做法,a、以时间换空间 b、以空间换时间。

<!--[if !supportLists]-->5、 <!--[endif]-->线程同步机制就是典型的“以时间换空间”,采用排队稍等的方法,一个个等待,直到前面一个用完,后面的才跟上,多人共用一个变量,用synchronized锁定排队。    

<!--[if !supportLists]-->6、 <!--[endif]-->ThreadLocal”就是典型的“以空间换时间”,她可以为每一个人提供一份变量,因此可以同时访问并互不干扰。

<!--[if !supportLists]-->7、 <!--[endif]-->言归正传:sessionFactory的属性dataSource设置成不用的数据源,首先不能在配置文件中写死,我们必须为她单独写一个类,让她来引用这个类,在这个类中再来判断我们到底要选择哪个数据源。

<!--[if !supportLists]-->8、 <!--[endif]-->我们把这类取个名字:MultiDataSource.,java,在这个类中要有DataSource的属性,还有方便我们取得配置文件中的数据源,我们还需要ApplicationContext这个属性,有这两个属性就够了。下面是我自己写的MultiDataSource类的源代码:

public class MultiDataSource implements DataSource {

private DataSource dateSource=null;

 

public void setDateSource(DataSource dateSource) {

this.dateSource = dateSource;

}

public DataSource getDateSource() {

return this. dateSource;

}

//其他实现方法自己写,主要是上面几个;

}

<!--[if !supportLists]-->9、 <!--[endif]-->在单例模式下,我们的系统中只有一个DataSource对象,我们每次调用MultiDataSource都可能是不同的,所以我们把DataSource放在实例变量中,最直接的方法是在getDataSource中告诉她,增加参数让她知道我们需要哪个数据源。

public DataSource getDateSource(String dataSourceName) {

try{

if(dataSourceName==null || dataSourceName.equals("")){

return this.dateSource;

}

return (DataSource)this.applicationContext.getBean(dataSourceName);}catch(NoSuchBeanDefinitionException ex){

return this.dateSource;

}

<!--[if !supportLists]-->10、 <!--[endif]-->}

 

<!--[if !supportLists]-->11、 <!--[endif]-->注意的是:DataSourceName就是配置文件中对应的数据源Id

 

ApplicationContext.xml中数据源的代码:

<bean id="DateSource1"

class="com.mchange.v2.c3p0.ComboPooledDataSource">

<property name="driverClass"

value="oracle.jdbc.driver.OracleDriver">

</property>

<property name="jdbcUrl"

value="jdbc:oracle:thin:@192.168.1.113:1521:orcl">

</property>

<property name="user" value="hycs"></property>

<property name="password" value="hycs"></property>

<property name="maxPoolSize" value="40"></property>

<property name="minPoolSize" value="1"></property>

<property name="initialPoolSize" value="1"></property>

<property name="maxIdleTime" value="20"></property>

</bean>

 

<bean id="DateSource2"

class="com.mchange.v2.c3p0.ComboPooledDataSource">

<property name="driverClass"

value="oracle.jdbc.driver.OracleDriver">

</property>

<property name="jdbcUrl"

value="jdbc:oracle:thin:@192.168.1.12:1521:orcl">

</property>

<property name="user" value="hycs"></property>

<property name="password" value="hycs"></property>

<property name="maxPoolSize" value="40"></property>

<property name="minPoolSize" value="1"></property>

<property name="initialPoolSize" value="1"></property>

<property name="maxIdleTime" value="20"></property>

<!--[if !supportLists]-->12、 <!--[endif]--></bean>

 

<!--[if !supportLists]-->13、 <!--[endif]-->再说一次sessionfactory*.xml中的配置

 

<bean id="multiDataSource" class="com.hy.datasource.MultiDataSource">

<property name="dateSource" ref="DateSource1"/>

</bean>

<bean id="sessionFactory"

class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

<property name="dataSource">

<ref bean="multiDataSource" />

</property>

。其他自己补上

</bean>

<!--[if !supportLists]-->14、 <!--[endif]-->sessionfactory的属性DataSource已经不是直接ref 配置文件中的数据源了。

<!--[if !supportLists]-->15、 <!--[endif]-->ref的是我们在自己编写的类,在一个封装类里面单独判断,这在外部是完全感觉不到我们数据源的改变。

<!--[if !supportLists]-->16、 <!--[endif]-->为了在类中得到ApplicationContext,我们必须让MultiDataSource实现org.springframework.context.ApplicationContextAware接口,并实现其方法: 

private ApplicationContext applicationContext=null;

public void setApplicationContext(ApplicationContext applicationContext) {

this.applicationContext = applicationContext;

}

<!--[if !supportLists]-->17、 <!--[endif]-->这样就可以通过this.applicationContext.getBean(dataSourceName)得到dataSource;

<!--[if !supportLists]-->18、 <!--[endif]-->写到这里差不多已经完毕了,但是页面上的数据源名字怎么通过request传到MultiDataSource类里呢,难道我们还要通过每个业务层和数据层一层层的传递数据源的名字吗?这样写也太多了吧。

在这里我们可以通过线程的方式跳过业务层和数据层直接把值传递到MultiDataSource类里public class SpObserver {

@SuppressWarnings("unchecked")

private static ThreadLocal<String> local = new ThreadLocal();

@SuppressWarnings("unchecked")

public static void putSp(String sp) {

local.set(sp);

}

public static String getSp() {

return local.get();

}

<!--[if !supportLists]-->19、 <!--[endif]-->}

 

<!--[if !supportLists]-->20、 <!--[endif]-->做一个filter,每一次请求的时候就调用SpObserver.putSp(dataSources);

 

request中的dataSourceName传给SpObserver对象并改变MultiDataSource类中getDataSource方法。public DataSource getDateSource() {

String sp=SpObserver.getSp();

return this.getDateSource(sp);

<!--[if !supportLists]-->21、 <!--[endif]-->}

<!--[if !supportLists]-->22、 <!--[endif]-->小小说明:每一次请求如果都发送数据源的名字未免也太麻烦了,可以在发送请求的时候把她保存在session中,如果下次没发请求的话,自己去session中取值,如果再发请求的时候就改变session中保存的值。

<!--[if !supportLists]-->23、 <!--[endif]-->总的来说就增加MultiDataSourceSpObserver两个类,其他的就是filter和配置文件的事了。下面我把详细的代码附上去;

MultiDataSource类的完整代码:

package com.hy.datasource;

import java.io.PrintWriter;

import java.sql.Connection;

import java.sql.SQLException;

import javax.sql.DataSource;

import org.springframework.beans.factory.NoSuchBeanDefinitionException;

import org.springframework.context.ApplicationContext;

import org.springframework.context.ApplicationContextAware;

 

public class MultiDataSource implements DataSource,ApplicationContextAware{

private DataSource dateSource=null;

private ApplicationContext applicationContext=null;

 

public Connection getConnection() throws SQLException {

// TODO Auto-generated method stub

return getDateSource().getConnection();

}

 

public Connection getConnection(String arg0, String arg1)

throws SQLException {

// TODO Auto-generated method stub

return null;

}

 

public PrintWriter getLogWriter() throws SQLException {

// TODO Auto-generated method stub

return null;

}

 

public int getLoginTimeout() throws SQLException {

// TODO Auto-generated method stub

return 0;

}

 

public void setLogWriter(PrintWriter arg0) throws SQLException {

// TODO Auto-generated method stub

 

}

 

public void setLoginTimeout(int arg0) throws SQLException {

// TODO Auto-generated method stub

 

}

 

public ApplicationContext getApplicationContext() {

return applicationContext;

}

 

public void setApplicationContext(ApplicationContext applicationContext) {

this.applicationContext = applicationContext;

}

 

public DataSource getDateSource(String dataSourceName) {

System.out.println("线程进来2");

try{

if(dataSourceName==null || dataSourceName.equals("")){

System.out.println("线程进来3");

return this.dateSource;

}

System.out.println("线程进来4");

return (DataSource)this.applicationContext.getBean(dataSourceName);//根据dataSourceName加载配置文件中的数据源对象

}catch(NoSuchBeanDefinitionException ex){

System.out.println("线程进来5");

return this.dateSource;

}

}

 

public void setDateSource(DataSource dateSource) {

System.out.println("dataSource方法");

this.dateSource = dateSource;

}

/**

 * 项目启动时,默认使用defaultDataSource

 * 用户选择时,根据选择数据源

 * ThreadLocal在单例下生成多个线程变量副本,解决多用户并发访问

 */

public DataSource getDateSource() {

System.out.println("线程进来1");

String sp=SpObserver.getSp();

return this.getDateSource(sp);

}

 

}

<!--[if !supportLists]-->24、 <!--[endif]-->SpObserver的完整代码:

<!--[if !supportLists]-->25、 <!--[endif]-->package com.hy.datasource;

public class SpObserver {

@SuppressWarnings("unchecked")

private static ThreadLocal<String> local = new ThreadLocal();

 

@SuppressWarnings("unchecked")

public static void putSp(String sp) {

System.out.println("set方法");

local.set(sp);

}

 

public static String getSp() {

System.out.println("get方法");

return local.get();

}

}

 

24MyFilter的完整代码:

public class MyFilter implements Filter {

 

public void destroy() {

// TODO Auto-generated method stub

 

}

 

public void doFilter(ServletRequest request, ServletResponse response,

FilterChain chain) throws IOException, ServletException {

HttpServletRequest req=(HttpServletRequest) request;

String dataSources=req.getParameter("dataSource");

String dataSource=(String) req.getSession().getAttribute("dataSource");

if(StringUtils.hasText(dataSources)){

SpObserver.putSp(dataSources);

}else if(StringUtils.hasText(dataSource)){

SpObserver.putSp(dataSource);

}

chain.doFilter(request, response);

}

 

public void init(FilterConfig arg0) throws ServletException {

// TODO Auto-generated method stub

 

}

 

}

<!--[if !supportLists]-->26、 <!--[endif]-->配置文件的部分配置:web.xml的过滤器配置

<filter>

<filter-name>dsFilter</filter-name>

<filter-class>com.hy.datasource.MyFilter</filter-class>

</filter>

<filter-mapping>

    <filter-name>dsFilter</filter-name>    

   <url-pattern>/*</url-pattern>    

</filter-mapping>

27.ApplicationContext.xml

<bean id="DateSource1"

class="com.mchange.v2.c3p0.ComboPooledDataSource">

<property name="driverClass"

value="oracle.jdbc.driver.OracleDriver">

</property>

<property name="jdbcUrl"

value="jdbc:oracle:thin:@192.168.1.113:1521:orcl">

</property>

<property name="user" value="hycs"></property>

<property name="password" value="hycs"></property>

<property name="maxPoolSize" value="40"></property>

<property name="minPoolSize" value="1"></property>

<property name="initialPoolSize" value="1"></property>

<property name="maxIdleTime" value="20"></property>

</bean>

 

<bean id="DateSource2"

class="com.mchange.v2.c3p0.ComboPooledDataSource">

<property name="driverClass"

value="oracle.jdbc.driver.OracleDriver">

</property>

<property name="jdbcUrl"

value="jdbc:oracle:thin:@192.168.1.12:1521:orcl">

</property>

<property name="user" value="hycs"></property>

<property name="password" value="hycs"></property>

<property name="maxPoolSize" value="40"></property>

<property name="minPoolSize" value="1"></property>

<property name="initialPoolSize" value="1"></property>

<property name="maxIdleTime" value="20"></property>

</bean>

<bean id="multiDataSource" class="com.hy.datasource.MultiDataSource">

<property name="dateSource" ref="DateSource1"/>

</bean>

<bean id="sessionFactory"

class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

<property name="dataSource">

<ref bean="multiDataSource" />

</property>

<property name="hibernateProperties">

<props>

<prop key="hibernate.dialect">

org.hibernate.dialect.Oracle9Dialect

</prop>

</props>

</property>

<property name="mappingResources">

<list>

<value>com/hy/bean/Job.hbm.xml</value>

<value>com/hy/bean/News.hbm.xml</value>

<value>com/hy/bean/ProductInfo.hbm.xml</value>

<value>com/hy/bean/Sort.hbm.xml</value>

<value>com/hy/bean/Userinfo.hbm.xml</value>

<value>com/hy/bean/Message.hbm.xml</value>

</list>

</property>

</bean>

 

总结:

1、上面的方案是针对不同数据库但表的结构完全一样而设计的,用的是同一个sessionfactory

2、如果是针对用户使用不同数据库且不同的表结构

类似的可以根据上面的设计搞定不同的sessionfactory,也可以写一个MultiSessionFactory的类来实现(提示:如果多个数据库是不同时使用才需要这样做,如果多个数据库是同时使用,就不必写了,直接在配置文件中几个数据库就配置几个sessionfactory就行了)。

3、还有一种情况是不同数据库有些表结构一样有些不一样:如果一样的就用同个sessionfactory,不同个dataSource,不一样的就在页面传入sessionfactoryNamedataSourceName,让他们分别对号入座就行了!

<!--EndFragment-->

 

分享到:
评论

相关推荐

    购物车模块设计及实现(SSH架构)

    ### 购物车模块设计及实现(SSH架构) #### 一、系统需求分析 **1.系统介绍** 本系统旨在构建一个高效、稳定的在线购物车模块,适用于网上书店等电子商务平台。通过采用SSH(Struts2 + Spring + Hibernate)框架,...

    ssh_test.rar_DataSourceSwitcher_ssh_test

    在标签中,“datasourceswitcher”可能是指一种在运行时动态切换数据源的工具或库,这对于处理多数据库环境或者需要根据业务需求动态调整读写策略的应用程序非常有用。“ssh_test_”标签进一步确认了这是一个SSH框架...

    velocity+ssh2+分页+权限

    总结,"velocity+ssh2+分页+权限"的整合涉及到Web开发中的多个关键环节,包括模板引擎的使用、MVC架构的实现、数据的分页展示以及安全的权限控制。通过这样的整合,开发者可以构建出高效、安全且易于维护的企业级...

    基于ssh2的网站内容管理系统源码下载

    6. **多语言支持**:适应全球化需求,提供多语言版本切换。 7. **统计分析**:提供对内容访问量、用户行为等数据的统计分析功能。 8. **API接口**:可能与其他系统或服务集成,如社交媒体分享、数据分析工具等。 **...

    基于MyEclipse的SSH框架搭建

    View-Controller)架构模式,Spring负责管理和协调应用程序的组件,以及提供AOP(面向切面编程)和IOC(控制反转)功能,而Hibernate则是强大的ORM(对象关系映射)框架,使得Java对象可以直接与数据库进行交互。...

    DBeaver数据库连接工具

    它支持多种数据库系统,包括但不限于MySQL、DB2和Oracle,使得用户无需切换不同的工具就能管理和操作各种类型的数据库。下面我们将详细探讨DBeaver的主要特性和使用方法。 1. **多数据库支持** DBeaver的亮点之一...

    围绕分页的练习(1)(ssh+freemarker)

    SSH是一个流行的企业级Java web应用开发框架,而Freemarker则是一种动态模板语言,常用于视图层的渲染。 在这个练习中,开发者可能需要了解以下知识点: 1. **Spring框架**:Spring是Java应用程序中的核心框架,...

    SSH整合(登录实例).doc

    根据给定文件的信息,本文将深入探讨如何在MyEclipse 8.0环境中整合Struts2、...整个过程中,重点在于框架的整合、资源的正确配置和代码的规范编写,确保项目既遵循了SSH架构的设计原则,又能高效地实现业务需求。

    ssh+compass实现站内搜索分页.rar

    SSH(Struts2 + Spring + Hibernate)是一种经典的Java Web...这一过程涉及到Java Web开发的多个层面,包括MVC架构、数据库操作、全文检索以及用户体验设计。熟练掌握这些技能将有助于构建高效且功能丰富的Web应用。

    ssh整合基本jar包

    Hibernate支持多种数据库,包括MySQL,通过配置hibernate.cfg.xml文件,可以轻松切换不同的数据库驱动。 在"ssh整合基本jar包"中,包含了用于SSH整合所需的基础库,包括Spring、Struts和Hibernate的jar包,以及...

    SSH项目开发需要引入的JAR包

    每个项目的具体需求可能会有所不同,因此在选择JAR包时,应确保它们与项目所使用的SSH框架版本兼容。同时,注意配置相应的XML文件(如struts.xml、spring-servlet.xml、hibernate.cfg.xml)来初始化和配置这些框架。

    ssh所有jar包

    这些jar包的完整列表可能包括但不限于上述组件,实际内容会根据SSH项目的具体配置和需求而变化。开发者在使用这些jar包时,需要确保版本兼容性,避免出现类冲突或功能缺失的问题。同时,为了优化项目结构和减少部署...

    SSH框架工作原理.doc

    总之,SSH框架通过分层架构、组件解耦以及强大的持久化支持,提升了开发效率和代码质量,适应了软件开发过程中需求变化和技术更新的挑战。尽管对于小型项目,直接使用PHP或ASP等技术可能会更快,但在大型企业级应用...

    ssh框架整合分页--内部类回调函数

    SSH框架整合分页——内部类回调函数 SSH(Spring、Struts2、Hibernate)是Java Web开发中常用的一种集成框架,它将Spring的IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面...

    ssh开发架包

    SSH开发架包,全称Struts2 + Spring + Hibernate整合框架,是Java Web开发中广泛使用的一种开源架构。这个框架集合了三个强大的组件,旨在简化应用程序的开发过程,提高开发效率,同时也增强了代码的可维护性和可...

    架构Mysql的软件Navicat for MySQL

    用户可以管理多个数据库连接,并进行切换,方便在不同项目间快速跳转。 #### 2.2 数据库设计 Navicat提供了一整套数据库设计工具,包括数据模型设计、表设计、视图设计等。用户可以通过可视化方式创建和修改表结构...

    基于SSH的OA办公系统(ORacle版)

    1. 工作流引擎:通过Struts2和Spring的配合,实现灵活的工作流定义和管理,可以自定义审批流程,满足不同企业的业务需求。 2. 数据安全:Oracle的强安全特性保障了用户数据的安全,结合Spring的安全管理,实现权限...

    中小企业web集群架构实战案例

    MySQL以其高性能、可靠性和灵活性而闻名,支持多种存储引擎,可以满足不同场景的需求。在Web集群架构中,MySQL通常用于存储用户数据、网站内容等关键信息。 ##### 1.4 NFS: NFS(Network File System)是一种分布式...

Global site tag (gtag.js) - Google Analytics