ssh架构依照需求动态切换不同的数据库ITeye - AG环亚娱乐

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

2019-01-11 11:00:52 | 作者: 以珊 | 标签: 不同,数据库,数据源 | 浏览: 1280

 

!--[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"

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"

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" 

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

/bean

bean id="sessionFactory"

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]-- 总的来说就添加MultiDataSource和SpObserver两个类,其他的便是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();

}

}

 

24、MyFilter的完好代码:

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"

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"

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" 

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

/bean

bean id="sessionFactory"

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,不相同的就在页面传入sessionfactoryName和dataSourceName,让他们别离对号入座就行了!

!--EndFragment--

 

版权声明
本文来源于网络,版权归原作者所有,其内容与观点不代表AG环亚娱乐立场。转载文章仅为传播更有价值的信息,如采编人员采编有误或者版权原因,请与我们联系,我们核实后立即修改或删除。

猜您喜欢的文章