您的位置:首页 > 编程语言 > Java开发

hibernate+spring 连接多个数据库,动态切换(多帐套)的实现

2013-06-14 12:31 681 查看
在现实应用中,可能我们后台所有连接的数据库可能不止一个,有可能要求一套代码同时可以连接多个数据库,并且要求在多个数据库中动态切换,本人也遇到这样的需求,就把自己的解决方案分享一下,该方法值针对hibernate+spring框架。

说先来说一下,我的这个需求:

先来讲一下帐套的概念:

按我的理解,帐套就是一个帐套就是一个数据库的映射。如后台有数据库a,b,c,那么我就建有一个映射

帐套a ---数据库a

帐套b---数据库b

帐套c---数据库c

用户看到的是帐套a,帐套b,帐套c,但是程序操作的数据库a,数据库b,数据库c,即当用户选择帐套a,程序对应的数据库就是数据库a,当用户选择帐套b,程序对应的数 据库就是b。

需求:

用户再登陆时,用户可以选择要登录的帐套(帐套就是一个队数据库的映射),要同时允许多个用户在登陆不同的帐套,也就是说程序对应的数据库,一直在不停地变化着,因为每个用户选择的帐套不同,程序操作的数据库就不同。

解决思路:

通过对需求分析,可以得到结论就是:每一个用户都操作着一个帐套,每一个帐套都对应着一个数据库,这里也可以说是一个对照表如:

用户1--帐套a

用户2--帐套b

根据帐套和数据库的映射,可以得到

用户1--数据库a

用户2--数据库b

因为我的是web应用,所以每一个用户就是一个会话(session),所以我用session的sessioinId作为用户的唯一标识。当用户在登陆系统时会被要求选择一个帐套,这个帐套会session绑在一起,作为一组键值对,存在放内存中,用户的每一次请求,都会根据sessionid获取到当前这个sessionId对应的帐套,进而获取到对应的数据库,然后将数据库切换为该sessionId 对应的数据。

原理都已经讲清楚,现在只需要实现2点,

1.记录每一个session对应的帐套

2.每一次请求切换对应的数据库

以下,讲一下如何实现这两点

记录每一个session对应的帐套

维护2个map,一个是当前线程map,另一个是sessionIdMap,在登陆时将用户信息和帐套信息写人

public class SpObserver {

/**

*description:

*@author lwq

*/

@SuppressWarnings("unchecked")

private static ThreadLocal local = new ThreadLocal();

@SuppressWarnings("unchecked")

//当前线程---数据库名称

public static void putSp(String dbName) {

local.set(dbName);

}

public static String getSp() {

return (String)local.get();

}

}

public class SessionMap {

/**

*description:

*@author lwq

*/

@SuppressWarnings("unchecked")

private static Map sessionMap=new HashMap();

@SuppressWarnings("unchecked")

public static void put(String sessionId,String dbName){

remove(sessionId);

sessionMap.put(sessionId, dbName);

}

public static void remove(String sessionId){

if(sessionMap.containsKey(sessionId)){

sessionMap.remove(sessionId);

}

}

public static String get(String sessionId){

if(sessionMap.containsKey(sessionId)){

String dbName=(String)sessionMap.get(sessionId);

return dbName;

}else{

return null;

}

}

//可以判断有多少个客户端

public static int getSize(){

return sessionMap.size();

}

}

切换数据库

配置dataSource

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

<property name="driverClassName" value="${jdbc.driverClassName}" />

<property name="url" value="${jdbc.url}" />

<property name="username" value="${jdbc.username}" />

<property name="password" value="${jdbc.password}" />

</bean>

<bean id="multiDataSource" class="com.onesun.common.system.MultiDataSource">

<property name="dataSource">

<ref bean="dataSource"/>

</property>

</bean>

在实现一个BasicDataSource,

public class MultiDataSource implements DataSource,ApplicationContextAware{

....

public DataSource getDataSource(){

String sp = SpObserver.getSp();

String dbName=SessionMap.get(sp);

return getDataSource(dbName);

}

public DataSource getDataSource(String dbName) {

System.out.println("数据库:"+dbName);

try{

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

return this.dataSource;

}

return (DataSource)this.applicationContext.getBean(dbName);

}catch(Exception e ){

try{

return this.loadDataSource(dbName);

}catch(Exception e2){

return this.createDataSource(dbName);

}

}

}

...

}

dbName就是数据库名称,应该还要对应着一个dbName.xml内容如下

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="wxtl" class="org.apache.commons.dbcp.BasicDataSource">

<property name="driverClassName" value="com.mysql.jdbc.Driver"/>

<property name="url" value="jdbc:mysql://127.0.0.1:3306/dbName"/>

<property name="username" value="root"/>

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

</bean>

</beans>

以上都只是一个思路,没有完整的代码,希望能给正在寻求解决方案的朋友帮助
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐