`

J2EE动态数据源使用方法

 
阅读更多
情况:

因项目需要,需要使用动态数据源,什么叫动态数据源,就是数据源是由客户动态选择的,不仅仅有一个。这就意味在后台会配置多个数据源。

 

我们的系统有很多版本,不同版本开发在不同的数据库上,但是系统需要的一些配置依赖于数据库,所以需要有一个能配置数据源的后台,让开发人员自己处理。

 

解决方案:

 

数据库datasource,需要继承AbstractRoutingDataSource ,在spring包里面。
Java代码  收藏代码

    /** 
     * <p> 
     * Title: 动态获取数据源 
     * </p> 
     *  
     * <p> 
     * Description:  
     * </p> 
     *  
     * <p> 
     * Copyright: 融博技术有限公司 2010 
     * </p> 
     *  
     * @author 袁泉锋HO174959 
     * @version 1.0 
     * @date Jul 23, 2010 
     * 
     */  
    public class CustomerRoutingDataSource extends AbstractRoutingDataSource {  
      
     /** 
      * <Description>寻找当前线程数据库Key值 
      * 
      * @since Jul 23, 2010 
      * @return <Description> 
      * 
      */  
     @Override  
     protected Object determineCurrentLookupKey() {  
      return CustomerContextHolder.getDataBase();     
     }  
    }  

 

AbstractRoutingDataSource 做了简单处理,我是反编译的,然后将属性targetDataSources修改为了map结构,key为数据源的ID,value是正常的datasource,看下面的spring配置文件:
Java代码  收藏代码

    package com.rb.util;  
      
      
      
    import java.sql.Connection;  
    import java.sql.SQLException;  
    import java.util.*;  
    import javax.sql.DataSource;  
    import org.springframework.beans.factory.InitializingBean;  
    import org.springframework.jdbc.datasource.AbstractDataSource;  
    import org.springframework.jdbc.datasource.lookup.DataSourceLookup;  
    import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;  
    import org.springframework.util.Assert;  
      
      
    public abstract class AbstractRoutingDataSource extends AbstractDataSource  
            implements InitializingBean {  
      
        public AbstractRoutingDataSource() {  
            dataSourceLookup = new JndiDataSourceLookup();  
        }  
      
        public void setTargetDataSources(Map targetDataSources) {  
            this.targetDataSources = targetDataSources;  
        }  
        public Map getTargetDataSources() {  
            return this.targetDataSources;  
        }  
        public void setDefaultTargetDataSource(Object defaultTargetDataSource) {  
            this.defaultTargetDataSource = defaultTargetDataSource;  
        }  
      
        public void setDataSourceLookup(DataSourceLookup dataSourceLookup) {  
            this.dataSourceLookup = ((DataSourceLookup) (dataSourceLookup == null ? ((DataSourceLookup) (new JndiDataSourceLookup()))  
                    : dataSourceLookup));  
        }  
      
        public void afterPropertiesSet() {  
            if (targetDataSources == null)  
                throw new IllegalArgumentException("targetDataSources is required");  
            resolvedDataSources = new HashMap(targetDataSources.size());  
            Object lookupKey;  
            DataSource dataSource;  
            for (Iterator it = targetDataSources.entrySet().iterator(); it  
                    .hasNext(); resolvedDataSources.put(lookupKey, dataSource)) {  
                java.util.Map.Entry entry = (java.util.Map.Entry) it.next();  
                lookupKey = resolveSpecifiedLookupKey(entry.getKey());  
                dataSource = resolveSpecifiedDataSource(entry.getValue());  
            }  
      
            if (defaultTargetDataSource != null)  
                resolvedDefaultDataSource = resolveSpecifiedDataSource(defaultTargetDataSource);  
        }  
      
        protected DataSource resolveSpecifiedDataSource(Object dataSource)  
                throws IllegalArgumentException {  
            if (dataSource instanceof DataSource)  
                return (DataSource) dataSource;  
            if (dataSource instanceof String)  
                return dataSourceLookup.getDataSource((String) dataSource);  
            else  
                throw new IllegalArgumentException(  
                        "Illegal data source value - only [javax.sql.DataSource] and String supported: "  
                                + dataSource);  
        }  
      
        public Connection getConnection() throws SQLException {  
            return determineTargetDataSource().getConnection();  
        }  
      
        public Connection getConnection(String username, String password)  
                throws SQLException {  
            return determineTargetDataSource().getConnection(username, password);  
        }  
      
        protected DataSource determineTargetDataSource() {  
            Assert  
                    .notNull(resolvedDataSources,  
                            "DataSource router not initialized");  
            Object lookupKey = determineCurrentLookupKey();  
            DataSource dataSource = (DataSource) resolvedDataSources.get(lookupKey);  
            if (dataSource == null)  
                dataSource = resolvedDefaultDataSource;  
            if (dataSource == null)  
                throw new IllegalStateException(  
                        "Cannot determine target DataSource for lookup key ["  
                                + lookupKey + "]");  
            else  
                return dataSource;  
        }  
      
        protected Object resolveSpecifiedLookupKey(Object lookupKey) {  
            return lookupKey;  
        }  
      
        protected abstract Object determineCurrentLookupKey();  
      
        private Map targetDataSources;  
      
        private Object defaultTargetDataSource;  
      
        private DataSourceLookup dataSourceLookup;  
      
        private Map resolvedDataSources;  
      
        private DataSource resolvedDefaultDataSource;  
    }  
      
      
    /* 
        DECOMPILATION REPORT 
     
        Decompiled from: E:\myeclipse6.0_project\ToolServerFlex\WebRoot\WEB-INF\lib\spring.jar 
        Total time: 218 ms 
        Jad reported messages/errors: 
    The class file version is 48.0 (only 45.3, 46.0 and 47.0 are supported) 
        Exit status: 0 
        Caught exceptions: 
    */  

 

 

CustomerContextHolder如下:
Java代码  收藏代码

    /** 
     * <p> 
     * Title: 动态获取数据源 
     * </p> 
     *  
     * <p> 
     * Description:  
     * </p> 
     *  
     * <p> 
     * Copyright: 融博技术有限公司 2010 
     * </p> 
     *  
     * @author 袁泉锋HO174959 
     * @version 1.0 
     * @date Jul 23, 2010 
     * 
     */  
    public class CustomerContextHolder {  
        private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();  
      
        public   static void setDataBase(String dataBase) {  
            contextHolder.set(dataBase);  
        }  
      
        public static String getDataBase() {  
            return (String) contextHolder.get();  
        }  
      
        public static void clearDataBase() {  
            contextHolder.remove();  
        }  
      
    }  

 开发人员请求过来的时候,调用方法setDataBase,将数据库配置key放入线程变量中。

 

自己定义一个数据库事务管理器:
Java代码  收藏代码

    package com.rb.util;  
      
    import java.sql.Connection;  
    import java.sql.SQLException;  
      
    import javax.sql.DataSource;  
      
    public class TransactionManager {  
        //private Connection conn;  
        private DataSource dataSource;  
        public static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();  
          
        public DataSource getDataSource() {  
            return dataSource;  
        }  
        public void setDataSource(DataSource dataSource) {  
            this.dataSource = dataSource;  
        }  
        public TransactionManager() {  
        }  
          
    //  public synchronized Connection  getConnection(){  
    //      Connection conn = tl.get();  
    //      if(conn==null){  
    //          try {  
    //              conn = dataSource.getConnection();  
    //          } catch (SQLException e) {  
    //              e.printStackTrace();  
    //          }  
    //          tl.set(conn);  
    //      }  
    //      return conn;  
    //  }  
        /** 开启事务 */  
        public void beginTransaction() throws SQLException{  
            try {  
                Connection conn = tl.get();  
                if(conn==null){  
                    conn = dataSource.getConnection();  
                    tl.set(conn);  
                }  
                conn.setAutoCommit(false); //把事务提交方式改为手工提交  
            } catch (SQLException e) {  
                throw new SQLException("开户事务时出现异常");  
            }  
        }  
        /** 提交事务并关闭连接 */  
        public void commitAndClose() throws SQLException{  
            Connection conn  = null;  
            try {  
                conn = tl.get();  
                conn.commit(); //提交事务  
            } catch (SQLException e) {  
                throw new SQLException("提交事务时出现异常");  
            }finally{  
                if(conn!=null){  
                    conn.close();  
                }  
                tl.remove(); //卸装线程绑定  
            }  
        }  
        /** 回滚并关闭连接 */  
        public void rollbackAndClose()throws SQLException{  
            Connection conn  = null;  
            try {  
                conn = tl.get();  
                conn.rollback();  
            } catch (SQLException e) {  
                throw new SQLException("回滚事务时出现异常");  
            } finally{  
                if(conn!=null){  
                    conn.close();  
                }  
                tl.remove(); //卸装线程绑定  
            }  
        }  
    }  

 调用完setDataBase方法之后,调用beginTransaction方法,第一次取的时候,connection是null,然后去datasource取连接,这个时候的datasource里面有很多数据源的连接,因为是一个map结构。当调用conn = dataSource.getConnection();的时候,会调用AbstractRoutingDataSource类的

方法:
Java代码  收藏代码

    public Connection getConnection() throws SQLException {  
      return determineTargetDataSource().getConnection();  
     }  

 

然后是:
Java代码  收藏代码

    protected DataSource determineTargetDataSource() {  
            Assert  
                    .notNull(resolvedDataSources,  
                            "DataSource router not initialized");  
            Object lookupKey = determineCurrentLookupKey();  
            DataSource dataSource = (DataSource) resolvedDataSources.get(lookupKey);  
            if (dataSource == null)  
                dataSource = resolvedDefaultDataSource;  
            if (dataSource == null)  
                throw new IllegalStateException(  
                        "Cannot determine target DataSource for lookup key ["  
                                + lookupKey + "]");  
            else  
                return dataSource;  
        }  

 里面会用到方法:
Java代码  收藏代码

    Object lookupKey = determineCurrentLookupKey();  

 但是我们的子类重写了他,是去线程变量里面取刚才我们setDataBase进去的,所以只会取到一个datasource。

这样就能取到自己选择的数据库连接了。

 

分享到:
评论

相关推荐

    j2ee编程技术源代码

    **J2EE编程技术源代码**是针对郝玉龙教授所著《J2EE编程技术》一书(北方交通大学出版社出版)所提供的配套源码。这本书深入浅出地讲解了Java企业级应用开发的关键技术,包括Servlet、JSP、Tag库以及EJB等核心组件。...

    J2EE项目案例源代码

    **J2EE项目案例源代码详解** J2EE(Java 2 Platform, Enterprise Edition)是Java平台上用于构建企业级分布式应用程序的框架。它提供了一系列的服务和API,支持多层架构,包括Web层、业务逻辑层和数据访问层,旨在...

    J2EE基础:JNDI定义Oracle数据源的方法

    通过以上步骤,你就可以在J2EE应用中使用JNDI来管理和使用Oracle数据源了。这不仅可以优化数据库连接管理,还能提高应用的并发处理能力。理解并熟练掌握JNDI和数据连接池的配置,是成为一名专业的IT从业者必备的技能...

    j2ee技术专题(包含有很多源代码)

    3. **层次(Layers)**:典型的J2EE架构采用四层模型,即客户端、Web层、业务逻辑层(EJB层)和数据访问层。 4. **容器(Containers)**:每个组件都有相应的容器来管理其生命周期,如Web容器(Servlet容器)和EJB...

    J2EE二手市场源代码

    3. Microsoft Access数据库的使用,包括数据源配置。 4. 使用JSP进行动态网页开发。 5. 可能涉及的前端技术,如HTML、CSS、JavaScript,以及可能的微信小程序开发。 6. 项目组织结构和源码管理。 对于开发者来说,...

    公司内部j2ee开发框架源代码

    【公司内部j2ee开发框架源代码】是一个典型的Java企业级应用开发框架,它结合了Struts和Hibernate两大主流技术,旨在提供一个高效、稳定且易于维护的开发环境。Struts是MVC(模型-视图-控制器)设计模式的一个实现,...

    J2EE 电子相册 源代码

    5. **JNDI(Java Naming and Directory Interface)**:JNDI提供了查找和绑定服务,使得应用能够查找和访问J2EE容器提供的各种资源,如数据源、邮件服务器等。 6. **JTA(Java Transaction API)**:对于涉及多资源...

    J2EE编程技术源代码 作者:郝玉龙

    在J2EE环境中,Servlet常与JavaServer Pages(JSP)结合使用,实现动态网页的生成。 **JSP(JavaServer Pages)**是一种基于Java的动态网页技术,它允许开发者在HTML页面中嵌入Java代码,从而实现页面的动态化。JSP...

    J2EE基础练习源代码

    **J2EE基础练习源代码**是一份专为初学者设计的编程资源,涵盖了JSP、Struts2、Hibernate、Spring以及Ajax等关键的Java企业级开发技术。这份压缩包包含了一系列示例代码,旨在帮助新手逐步理解并掌握这些技术的基础...

    j2ee源代码 案例代码

    5. **CH6:JNDI(Java Naming and Directory Interface)** - 解释如何查找和绑定资源,如数据源和EJBs。 6. **CH7:JTA(Java Transaction API)** - 介绍事务管理,如何处理分布式事务。 7. **CH8:过滤器和监听...

    J2EE项目案例源代码(强力推荐:运行稳定)

    使用AJAX(Asynchronous JavaScript and XML)可以提高页面的动态性和响应速度。通过研究这些源代码,我们可以学习到如何将后端服务与前端UI紧密结合,提升用户体验。 此外,标签中的"java"提示我们,这个J2EE项目...

    j2ee课程数据源码

    6. **配置文件**:J2EE应用通常有XML配置文件,如Spring的`applicationContext.xml`和`web.xml`,用来配置bean、数据源、事务管理器等。 7. **依赖库**:项目可能包含了所需的JAR文件,如JDBC驱动、Spring框架、...

    J2EE案例开发(源代码)

    6. **JNDI(Java Naming and Directory Interface)**:JNDI提供了一个查找和绑定对象的接口,常用于查找EJB、数据源和其他服务。在源代码中,你可能会看到如何通过JNDI查找和引用企业级组件。 7. **MVC(Model-...

    J2EE 应用开发源代码

    标题 "J2EE 应用开发源代码" 涉及到的是Java企业版(Java 2 Platform, Enterprise Edition,简称J2EE)的开发实践,这是一个用于构建可扩展、多层、分布式的企业级应用程序的平台。这个压缩包可能包含了多个章节的源...

    《精通J2EE》部分源程序一

    《精通J2EE》部分源程序一,这个资源包含了学习J2EE开发的重要实践内容,主要聚焦于Eclipse、Struts、Hibernate、Spring这四大框架的整合应用。J2EE,全称为Java 2 Platform, Enterprise Edition,是Java平台的企业...

    j2ee设计模式源代码

    在J2EE应用中,如数据源管理或线程池,常使用单例模式。 2. **工厂模式**:提供创建对象的接口,但让子类决定实例化哪一个类。在EJB中,容器会根据部署描述符自动创建Bean实例,这就是一种工厂模式的应用。 3. **...

    j2ee 源代码 集合

    本集合包含了几个关键组件的源代码,这对于理解J2EE工作原理、进行深入学习和自定义开发是极其宝贵的资源。 首先,`apache-tomcat-6.0.18-src.zip`是Apache Tomcat的源代码,Tomcat是一个开源的Servlet容器,实现了...

    J2EE课件及源代码 大连理工大学软件学院

    本章将深入探讨JavaBean的设计原则、属性、构造器和方法,以及如何在Servlet和JSP中使用。 五、自定义标记 5. **第6章 自定义标记**:自定义标记是JSP的一种扩展,可以提高代码的可读性和复用性。本章将介绍如何...

    J2EE 0.2—加入dao\\dataSource\\jdbcTemplate等联系方法

    在J2EE应用中,dataSource通常由应用服务器管理,例如Tomcat、WebLogic或JBoss等,它们能够配置多个数据源以连接不同的数据库。 接下来,我们来探讨jdbcTemplate,它是Spring框架的一部分,用于简化JDBC操作。...

    我的j2ee成功之路源代码_16_17_18.zip

    - **JTA**:支持分布式事务,确保跨多个数据源的操作一致性。 - **EJB**:提供面向服务的组件模型,可以创建可复用的、安全的、事务性的企业级服务。 通过学习和实践这些j2EE源代码,开发者可以深入了解如何设计和...

Global site tag (gtag.js) - Google Analytics