一、 目的
不同的用户登录到具有表结构相同的各自数据库(一个oracle 服务器),来操作各自的数据,而dao 不知道这些改变。
二、 实现方法
1、分析applicationContext.xml
数据源bean配置
xml 代码
- <bean id="dataSource" singleton="true"
- class="org.apache.commons.dbcp.BasicDataSource">
- <property name="driverClassName">
- <value>oracle.jdbc.driver.OracleDrivervalue>
- property>
- <property name="url"> <value>jdbc:oracle:thin:@192.168.0.254:1521:CARRYDLvalue>
- property>
- <property name="username">
- <value>oavalue>
- property>
- <property name="password">
- <value>oavalue>
- property>
- bean>
- Session 工厂的配置
- <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
- <property name="dataSource">
- <ref bean="dataSource" />
- property>
- <property name="mappingDirectoryLocations"> <list><value>classpath:/com/carry/hibernate/value>list>
- property>
- <property name="hibernateProperties">
- <props>
- <prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialectprop>
- <prop key="hibernate.c3po.min_size">5prop>
- <prop key="hibernate.c3po.max_size">20prop>
- <prop key="hibernate.c3po.timeout">1800prop>
- <prop key="hibernate.format_sql">trueprop>
- <prop key="hibernate.cglib.use_reflection_optimizer">trueprop>
- props>
- property>
- bean>
从上面配置文件可以看出,数据源和session 工厂是一一对应的。
如果配置多个数据源,就要配置多个session工厂,事务的代理就更加的麻烦,所以这样的方法不可取的。所以只能从数据源入手。
2、动态数据源框
由于spring 使用javax.sql.DataSource 统一接口。所以可以复写DataSource具体如下所示:
java 代码
- MultiDataSource.java
- package com.carry.spring.datasource;
- import java.io.PrintWriter;
- import java.sql.Connection;
- import java.sql.SQLException;
- import java.util.*;
- import javax.sql.DataSource;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.apache.commons.dbcp.BasicDataSource;
- /
- public class MultiDataSource implements DataSource{
- private static final Log log = LogFactory.getLog(MultiDataSource.class);
- private static final Map dataSources =new HashMap();///数据源对象池
- private DataSource dataSource = null;默认数据源用于测试的数据源
- public Connection getConnection() throws SQLException {
- return getDataSource().getConnection();
- }
- public Connection getConnection(String arg0, String arg1)
- throws SQLException {
- return getDataSource().getConnection(arg0, arg1);
- }
- public PrintWriter getLogWriter() throws SQLException {
- return getDataSource().getLogWriter();
- }
- public int getLoginTimeout() throws SQLException {
- return getDataSource().getLoginTimeout();
- }
- public void setLogWriter(PrintWriter arg0) throws SQLException {
- getDataSource().setLogWriter(arg0);
- }
- public void setLoginTimeout(int arg0) throws SQLException {
- getDataSource().setLoginTimeout(arg0);
- }
- public DataSource getDataSource(String dataSourceName)
- {
- log.debug("dataSourceName:"+dataSourceName);
- if(dataSourceName==null||dataSourceName.equals(""))
- {
- return this.dataSource;
- }
- if(dataSources.get(dataSourceName)!=null)
- {
- return (DataSource)dataSources.get(dataSourceName);
- }
- else
- {
- return createDataSource(SpObserver.getName(),SpObserver.getPass());
- }
- }
- public void setDataSource(DataSource dataSource) {
- this.dataSource = dataSource;
- }
- public DataSource getDataSource(){
- String sp = SpObserver.getName();
- return getDataSource(sp);
- }
- public DataSource createDataSource(String userName,String password)
- {
- BasicDataSource s =new BasicDataSource();
- BasicDataSource ts =(BasicDataSource)dataSource;
- //System.out.println(userName+"____"+password);
- s.setUsername(userName);
- s.setPassword(password);
- s.setUrl(ts.getUrl());
- s.setDriverClassName(ts.getDriverClassName());
- dataSources.put(userName, s);
- return s;
- }
- }
java 代码
- SpObserver.java
- package com.carry.spring.datasource;
- public class SpObserver {
- private static ThreadLocal <string></string> localName = new ThreadLocal<string></string>();
- private static ThreadLocal <string></string> localPass = new ThreadLocal <string></string> ();
- public static void putName(String sp)
- {
- localName.set(sp);
- }
- public static String getName()
- {
- return (String)localName.get();
- }
- public static void putPass(String sp)
- {
- localPass.set(sp);
- }
- public static String getPass()
- {
- return (String)localPass.get();
- }
- }
该类使用ThreadLocal 来存储数据库用户和密码保证数据的不冲突
MultiDataSource 需要和MVC 通讯来了解用户需要登录使用那一个数据库,所以必须有一个Filter 来对HttpServletRequest 对象进行监听,来获得登录数据的用户和密码。
如下代码
java 代码
- MyFilter.java
- package com.carry.spring.datasource;
- public class MyFilter implements Filter {
- public MyFilter() {
- }
- public void init(FilterConfig filterConfig) throws ServletException {
- }
- public void doFilter(ServletRequest request, ServletResponse response,
- FilterChain chain) throws IOException, ServletException
- {
- HttpServletRequest httpRequest = (HttpServletRequest) request;
- Object nobj=httpRequest.getSession().getAttribute("name");
- Object pobj=httpRequest.getSession().getAttribute("pass");
- if(nobj!=null && pobj!=null)
- {
- String name = nobj.toString();
- String pass = pobj.toString();
- SpObserver.putName(name);
- SpObserver.putPass(pass);
- System.out.println("使数据源"+name);
- }
- else
- {
- SpObserver.putName("");
- SpObserver.putPass("");
- System.out.println("用户未登录,使用默认数据源");
- }
- chain.doFilter(request, response);
- }
- public void destroy() {
- }
- }
xml 代码
- 新的applicationContext.xml 的配置文件如下
- <bean id="dataSource" singleton="true"
- class="org.apache.commons.dbcp.BasicDataSource">
- <property name="driverClassName">
- <value>oracle.jdbc.driver.OracleDrivervalue>
- property>
- <property name="url">
- <value>jdbc:oracle:thin:@192.168.0.254:1521:CARRYDLvalue>
- property>
- <property name="username">
- <value>oavalue>
- property>
- <property name="password">
- <value>oavalue>
- property>
- bean>
- <bean id="multiDataSource" singleton="true"
- class="com.carry.spring.datasource.MultiDataSource">
- <property name="dataSource">
- <ref bean="dataSource"/>
- property>
- bean>
- <bean id="sessionFactory"
- class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
- <property name="dataSource">
- <ref bean="multiDataSource"/>
- property>
- <property name="mappingDirectoryLocations">
- <list><value>classpath:/com/carry/hibernate/value>list>
- property>
- <property name="hibernateProperties">
- <props>
- <prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialectprop>
- <prop key="hibernate.c3po.min_size">5prop>
- <prop key="hibernate.c3po.max_size">20prop>
- <prop key="hibernate.c3po.timeout">1800prop>
- <prop key="hibernate.format_sql">trueprop>
- <prop key="hibernate.cglib.use_reflection_optimizer">trueprop>
- props>
- property>
- <property name="lobHandler" ref="lobHandler"/>
- bean>
- 红色为配置文件增加的部分
- Web.xml 的配置增加如下filter
- <filter>
- <filter-name>dataSourceFilterfilter-name>
- <filter-class>
- com.carry.spring.datasource.MyFilter
- filter-class>
- filter>
- <filter-mapping>
- <filter-name>dataSourceFilterfilter-name>
- <url-pattern>/*url-pattern>
- filter-mapping>