Spring动态加载、编辑数据源

来源:互联网 发布:淘宝买东西先付款 编辑:程序博客网 时间:2024/05/05 04:15


        最近有一个项目需求,要求实现SAAS服务,最终结果大致如上图,当然这只是其中的一部分。这个项目有一个很明确的需求:所有站点用的是一套代码,有一个主站,多个子站,所有子站的数据结构是一致的,A登录时访问子站一,B登录时访问子站二,子站一与子站二的数据分别位于不同的数据库中,数据内容互不影响。

        网上查了一些资料,总结并实践后得出此文。

        我项目中用的是Spring JPA Data,忽略大部分配置,主要配置如下所示:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee"  
  4.     xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"  
  5.     xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util"  
  6.     xmlns:cache="http://www.springframework.org/schema/cache" xmlns:jpa="http://www.springframework.org/schema/data/jpa"  
  7.     xmlns:tool="http://www.springframework.org/schema/tool" xmlns:context="http://www.springframework.org/schema/context"  
  8.     xmlns:jdbc="http://www.springframework.org/schema/jdbc"  
  9.     xsi:schemaLocation="http://www.springframework.org/schema/beans    
  10.      http://www.springframework.org/schema/beans/spring-beans-3.1.xsd  
  11.      http://www.springframework.org/schema/tx    
  12.      http://www.springframework.org/schema/tx/spring-tx-3.1.xsd  
  13.      http://www.springframework.org/schema/aop    
  14.      http://www.springframework.org/schema/aop/spring-aop.xsd    
  15.      http://www.springframework.org/schema/jee    
  16.      http://www.springframework.org/schema/jee/spring-jee.xsd    
  17.      http://www.springframework.org/schema/context    
  18.      http://www.springframework.org/schema/context/spring-context.xsd    
  19.      http://www.springframework.org/schema/cache  
  20.      http://www.springframework.org/schema/cache/spring-cache-3.1.xsd  
  21.      http://www.springframework.org/schema/data/jpa  
  22.      http://www.springframework.org/schema/data/jpa/spring-jpa.xsd  
  23.      http://www.springframework.org/schema/util    
  24.      http://www.springframework.org/schema/util/spring-util-3.1.xsd  
  25.      http://www.springframework.org/schema/jdbc   
  26.      http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd  
  27.      http://www.springframework.org/schema/tool    
  28.      http://www.springframework.org/schema/tool/spring-tool.xsd"  
  29.     default-lazy-init="true" default-autowire="byName">  
  30.   
  31.     <bean id="dataSource" class="${datasource.driver}">   
  32.         <property name="user" value="${datasource.username}" />   
  33.         <property name="password" value="${datasource.password}" />   
  34.         <property name="URL" value="${datasource.url}" />   
  35.     </bean>  
  36.   
  37.     <bean id="dynamicDataSource" class="com.gsoft.induasso.datasource.DynamicDataSource">  
  38.         <property name="targetDataSources">  
  39.             <map>  
  40.             </map>  
  41.         </property>  
  42.         <property name="defaultTargetDataSource" ref="dataSource" />  
  43.     </bean>  
  44.   
  45. </beans>  

        配置中引用了properties文件配置的值,具体如何实现不在此处描述。

        DynamicDataSource类的代码如下所示:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  *  
  3.  * @author Geloin 
  4.  * @date Jan 16, 2014 6:08:27 PM 
  5.  */  
  6. package com.gsoft.induasso.datasource;  
  7.   
  8. import java.sql.Connection;  
  9. import java.sql.PreparedStatement;  
  10. import java.sql.ResultSet;  
  11. import java.sql.SQLException;  
  12. import java.util.Map;  
  13.   
  14. import javax.sql.DataSource;  
  15.   
  16. import org.apache.commons.dbcp.BasicDataSource;  
  17. import org.apache.log4j.Logger;  
  18. import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;  
  19. import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;  
  20.   
  21. import com.gsoft.crystal.framework.core.util.Utils;  
  22. import com.gsoft.induasso.constant.Constants;  
  23.   
  24. /** 
  25.  *  
  26.  * @author Geloin 
  27.  * @date Jan 16, 2014 6:08:27 PM 
  28.  */  
  29. public class DynamicDataSource extends AbstractRoutingDataSource {  
  30.   
  31.     private Logger log = Logger.getLogger(this.getClass());  
  32.     private Map<Object, Object> _targetDataSources;  
  33.   
  34.     /** 
  35.      * @see org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource#determineCurrentLookupKey() 
  36.      * @describe 数据源为空或者为0时,自动切换至默认数据源,即在配置文件中定义的dataSource数据源 
  37.      */  
  38.     @Override  
  39.     protected Object determineCurrentLookupKey() {  
  40.         String dataSourceName = DbContextHolder.getDBType();  
  41.         if (dataSourceName == null) {  
  42.             dataSourceName = Constants.DEFAULT_DATA_SOURCE_NAME;  
  43.         } else {  
  44.             this.selectDataSource(dataSourceName);  
  45.         }  
  46.         log.debug("--------> use datasource " + dataSourceName);  
  47.         return dataSourceName;  
  48.     }  
  49.   
  50.     /** 
  51.      * 到数据库中查找名称为dataSourceName的数据源 
  52.      *  
  53.      * @author Geloin 
  54.      * @date Jan 20, 2014 12:15:41 PM 
  55.      * @param dataSourceName 
  56.      */  
  57.     private void selectDataSource(String dataSourceName) {  
  58.         Object sid = DbContextHolder.getDBType();  
  59.         if (Utils.isEmpty(dataSourceName)  
  60.                 || dataSourceName.trim().equals("dataSource")) {  
  61.             DbContextHolder.setDBType("dataSource");  
  62.             return;  
  63.         }  
  64.         Object obj = this._targetDataSources.get(dataSourceName);  
  65.         if (obj != null && sid.equals(dataSourceName)) {  
  66.             return;  
  67.         } else {  
  68.             DataSource dataSource = this.getDataSource(dataSourceName);  
  69.             if (null != dataSource) {  
  70.                 this.setDataSource(dataSourceName, dataSource);  
  71.             }  
  72.         }  
  73.     }  
  74.   
  75.     @Override  
  76.     public void setTargetDataSources(Map<Object, Object> targetDataSources) {  
  77.         this._targetDataSources = targetDataSources;  
  78.         super.setTargetDataSources(this._targetDataSources);  
  79.         afterPropertiesSet();  
  80.     }  
  81.   
  82.     private void addTargetDataSource(String key, DataSource dataSource) {  
  83.         this._targetDataSources.put(key, dataSource);  
  84.         this.setTargetDataSources(this._targetDataSources);  
  85.     }  
  86.   
  87.     private DataSource createDataSource(String driverClassName, String url,  
  88.             String username, String password) {  
  89.         BasicDataSource dataSource = new BasicDataSource();  
  90.         dataSource.setDriverClassName(driverClassName);  
  91.         dataSource.setUrl(url);  
  92.         dataSource.setUsername(username);  
  93.         dataSource.setPassword(password);  
  94.         return dataSource;  
  95.     }  
  96.   
  97.     /** 
  98.      * 到数据库中查询名称为dataSourceName的数据源 
  99.      *  
  100.      * @author Geloin 
  101.      * @date Jan 20, 2014 12:18:12 PM 
  102.      * @param dataSourceName 
  103.      * @return 
  104.      */  
  105.     private DataSource getDataSource(String dataSourceName) {  
  106.         this.selectDataSource(Constants.DEFAULT_DATA_SOURCE_NAME);  
  107.         this.determineCurrentLookupKey();  
  108.         Connection conn = null;  
  109.         try {  
  110.             conn = this.getConnection();  
  111.             StringBuilder builder = new StringBuilder();  
  112.             builder.append("SELECT C_NAME,C_TYPE,C_URL,C_USER_NAME,");  
  113.             builder.append("C_PASSWORD,C_JNDI_NAME,C_DRIVER_CLASS_NAME ");  
  114.             builder.append("FROM IA_DATA_SOURCE WHERE c_name = ?");  
  115.   
  116.             PreparedStatement ps = conn.prepareStatement(builder.toString());  
  117.             ps.setString(1, dataSourceName);  
  118.             ResultSet rs = ps.executeQuery();  
  119.             if (rs.next()) {  
  120.   
  121.                 Integer type = rs.getInt("C_TYPE");  
  122.                 if (Utils.isNotEmpty(type)  
  123.                         && type.intValue() == Constants.DataSourceType.DB  
  124.                                 .intValue()) {  
  125.                     // DB  
  126.                     String url = rs.getString("C_URL");  
  127.                     String userName = rs.getString("C_USER_NAME");  
  128.                     String password = rs.getString("C_PASSWORD");  
  129.                     String driverClassName = rs  
  130.                             .getString("C_DRIVER_CLASS_NAME");  
  131.                     DataSource dataSource = this.createDataSource(  
  132.                             driverClassName, url, userName, password);  
  133.                     return dataSource;  
  134.                 } else {  
  135.                     // JNDI  
  136.                     String jndiName = rs.getString("C_JNDI_NAME");  
  137.   
  138.                     JndiDataSourceLookup jndiLookUp = new JndiDataSourceLookup();  
  139.                     DataSource dataSource = jndiLookUp.getDataSource(jndiName);  
  140.                     return dataSource;  
  141.                 }  
  142.   
  143.             }  
  144.             rs.close();  
  145.             ps.close();  
  146.         } catch (SQLException e) {  
  147.             log.error(e);  
  148.         } finally {  
  149.             try {  
  150.                 conn.close();  
  151.             } catch (SQLException e) {  
  152.                 log.error(e);  
  153.             }  
  154.         }  
  155.         return null;  
  156.     }  
  157.   
  158.     /** 
  159.      * 将已存在的数据源存储到内存中 
  160.      *  
  161.      * @author Geloin 
  162.      * @date Jan 20, 2014 12:24:13 PM 
  163.      * @param dataSourceName 
  164.      * @param dataSource 
  165.      */  
  166.     private void setDataSource(String dataSourceName, DataSource dataSource) {  
  167.         this.addTargetDataSource(dataSourceName, dataSource);  
  168.         DbContextHolder.setDBType(dataSourceName);  
  169.     }  
  170.   
  171. }  

        其中使用的DbContextHolder类的内容如下所示:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  *  
  3.  * @author Geloin 
  4.  * @date Jan 16, 2014 6:08:47 PM 
  5.  */  
  6. package com.gsoft.induasso.datasource;  
  7.   
  8. /** 
  9.  *  
  10.  * @author Geloin 
  11.  * @date Jan 16, 2014 6:08:47 PM 
  12.  */  
  13. public class DbContextHolder {  
  14.   
  15.     private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();  
  16.   
  17.     public static void setDBType(String dbType) {  
  18.         contextHolder.set(dbType);  
  19.     }  
  20.   
  21.     public static String getDBType() {  
  22.         return (String) contextHolder.get();  
  23.     }  
  24.   
  25.     public static void clearDBType() {  
  26.         contextHolder.remove();  
  27.     }  
  28. }  

        文中还涉及到一个Entity类,如下所示:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  *  
  3.  * @author Geloin 
  4.  * @date Jan 17, 2014 10:17:32 AM 
  5.  */  
  6. package com.gsoft.induasso.entity;  
  7.   
  8. import javax.persistence.Column;  
  9. import javax.persistence.Entity;  
  10. import javax.persistence.GeneratedValue;  
  11. import javax.persistence.GenerationType;  
  12. import javax.persistence.Id;  
  13. import javax.persistence.SequenceGenerator;  
  14. import javax.persistence.Table;  
  15.   
  16. import com.gsoft.induasso.constant.Constants;  
  17.   
  18. /** 
  19.  *  
  20.  * @author Geloin 
  21.  * @date Jan 17, 2014 10:17:32 AM 
  22.  */  
  23. @Entity  
  24. @Table(name = "IA_DATA_SOURCE")  
  25. public class GsoftDataSource {  
  26.   
  27.     @Id  
  28.     @SequenceGenerator(name = "IA_DATA_SOURCE_SEQ", sequenceName = "IA_DATA_SOURCE_SEQ", allocationSize = 1)  
  29.     @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "IA_DATA_SOURCE_SEQ")  
  30.     private Long id;  
  31.   
  32.     /** 
  33.      * data source name 
  34.      */  
  35.     @Column(name = "C_NAME", unique = true)  
  36.     private String name;  
  37.   
  38.     /** 
  39.      * data source type, default is database<br /> 
  40.      * {@link Constants.DataSourceType} 
  41.      */  
  42.     @Column(name = "C_TYPE")  
  43.     private Integer type = Constants.DataSourceType.DB.intValue();  
  44.   
  45.     /** 
  46.      * 数据库类型,目前只支持MySql和Oracle<br /> 
  47.      * {@link Constants.DataType} 
  48.      */  
  49.     @Column(name = "C_DATA_TYPE")  
  50.     private Integer dataType = Constants.DataType.ORACLE.intValue();  
  51.   
  52.     @Column(name = "C_URL")  
  53.     private String url;  
  54.   
  55.     @Column(name = "C_USER_NAME")  
  56.     private String userName;  
  57.   
  58.     @Column(name = "C_PASSWORD")  
  59.     private String password;  
  60.   
  61.     @Column(name = "C_JNDI_NAME")  
  62.     private String jndiName;  
  63.   
  64.     @Column(name = "C_DRIVER_CLASS_NAME")  
  65.     private String driverClassName;  
  66.   
  67.     public Long getId() {  
  68.         return id;  
  69.     }  
  70.   
  71.     public void setId(Long id) {  
  72.         this.id = id;  
  73.     }  
  74.   
  75.     public Integer getType() {  
  76.         return type;  
  77.     }  
  78.   
  79.     public void setType(Integer type) {  
  80.         this.type = type;  
  81.     }  
  82.   
  83.     public String getUrl() {  
  84.         return url;  
  85.     }  
  86.   
  87.     public void setUrl(String url) {  
  88.         this.url = url;  
  89.     }  
  90.   
  91.     public String getUserName() {  
  92.         return userName;  
  93.     }  
  94.   
  95.     public void setUserName(String userName) {  
  96.         this.userName = userName;  
  97.     }  
  98.   
  99.     public String getPassword() {  
  100.         return password;  
  101.     }  
  102.   
  103.     public void setPassword(String password) {  
  104.         this.password = password;  
  105.     }  
  106.   
  107.     public String getJndiName() {  
  108.         return jndiName;  
  109.     }  
  110.   
  111.     public void setJndiName(String jndiName) {  
  112.         this.jndiName = jndiName;  
  113.     }  
  114.   
  115.     public String getName() {  
  116.         return name;  
  117.     }  
  118.   
  119.     public void setName(String name) {  
  120.         this.name = name;  
  121.     }  
  122.   
  123.     public String getDriverClassName() {  
  124.         return driverClassName;  
  125.     }  
  126.   
  127.     public void setDriverClassName(String driverClassName) {  
  128.         this.driverClassName = driverClassName;  
  129.     }  
  130.   
  131.     public Integer getDataType() {  
  132.         return dataType;  
  133.     }  
  134.   
  135.     public void setDataType(Integer dataType) {  
  136.         this.dataType = dataType;  
  137.     }  
  138.   
  139. }  

        常量类可忽略。


        在实际的场景中,IA_Data_Source表中保存了多条数据源记录(可以通过增删改查维护),在操作子站点数据时,只需要在每个Service方法中加上以下代码即可:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. DbContextHolder.setDBType("IA_DATA_SOURCE中某个数据源的name属性的值");  

        最近有一个项目需求,要求实现SAAS服务,最终结果大致如上图,当然这只是其中的一部分。这个项目有一个很明确的需求:所有站点用的是一套代码,有一个主站,多个子站,所有子站的数据结构是一致的,A登录时访问子站一,B登录时访问子站二,子站一与子站二的数据分别位于不同的数据库中,数据内容互不影响。

        网上查了一些资料,总结并实践后得出此文。

        我项目中用的是Spring JPA Data,忽略大部分配置,主要配置如下所示:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee"  
  4.     xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"  
  5.     xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util"  
  6.     xmlns:cache="http://www.springframework.org/schema/cache" xmlns:jpa="http://www.springframework.org/schema/data/jpa"  
  7.     xmlns:tool="http://www.springframework.org/schema/tool" xmlns:context="http://www.springframework.org/schema/context"  
  8.     xmlns:jdbc="http://www.springframework.org/schema/jdbc"  
  9.     xsi:schemaLocation="http://www.springframework.org/schema/beans    
  10.      http://www.springframework.org/schema/beans/spring-beans-3.1.xsd  
  11.      http://www.springframework.org/schema/tx    
  12.      http://www.springframework.org/schema/tx/spring-tx-3.1.xsd  
  13.      http://www.springframework.org/schema/aop    
  14.      http://www.springframework.org/schema/aop/spring-aop.xsd    
  15.      http://www.springframework.org/schema/jee    
  16.      http://www.springframework.org/schema/jee/spring-jee.xsd    
  17.      http://www.springframework.org/schema/context    
  18.      http://www.springframework.org/schema/context/spring-context.xsd    
  19.      http://www.springframework.org/schema/cache  
  20.      http://www.springframework.org/schema/cache/spring-cache-3.1.xsd  
  21.      http://www.springframework.org/schema/data/jpa  
  22.      http://www.springframework.org/schema/data/jpa/spring-jpa.xsd  
  23.      http://www.springframework.org/schema/util    
  24.      http://www.springframework.org/schema/util/spring-util-3.1.xsd  
  25.      http://www.springframework.org/schema/jdbc   
  26.      http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd  
  27.      http://www.springframework.org/schema/tool    
  28.      http://www.springframework.org/schema/tool/spring-tool.xsd"  
  29.     default-lazy-init="true" default-autowire="byName">  
  30.   
  31.     <bean id="dataSource" class="${datasource.driver}">   
  32.         <property name="user" value="${datasource.username}" />   
  33.         <property name="password" value="${datasource.password}" />   
  34.         <property name="URL" value="${datasource.url}" />   
  35.     </bean>  
  36.   
  37.     <bean id="dynamicDataSource" class="com.gsoft.induasso.datasource.DynamicDataSource">  
  38.         <property name="targetDataSources">  
  39.             <map>  
  40.             </map>  
  41.         </property>  
  42.         <property name="defaultTargetDataSource" ref="dataSource" />  
  43.     </bean>  
  44.   
  45. </beans>  

        配置中引用了properties文件配置的值,具体如何实现不在此处描述。

        DynamicDataSource类的代码如下所示:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  *  
  3.  * @author Geloin 
  4.  * @date Jan 16, 2014 6:08:27 PM 
  5.  */  
  6. package com.gsoft.induasso.datasource;  
  7.   
  8. import java.sql.Connection;  
  9. import java.sql.PreparedStatement;  
  10. import java.sql.ResultSet;  
  11. import java.sql.SQLException;  
  12. import java.util.Map;  
  13.   
  14. import javax.sql.DataSource;  
  15.   
  16. import org.apache.commons.dbcp.BasicDataSource;  
  17. import org.apache.log4j.Logger;  
  18. import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;  
  19. import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;  
  20.   
  21. import com.gsoft.crystal.framework.core.util.Utils;  
  22. import com.gsoft.induasso.constant.Constants;  
  23.   
  24. /** 
  25.  *  
  26.  * @author Geloin 
  27.  * @date Jan 16, 2014 6:08:27 PM 
  28.  */  
  29. public class DynamicDataSource extends AbstractRoutingDataSource {  
  30.   
  31.     private Logger log = Logger.getLogger(this.getClass());  
  32.     private Map<Object, Object> _targetDataSources;  
  33.   
  34.     /** 
  35.      * @see org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource#determineCurrentLookupKey() 
  36.      * @describe 数据源为空或者为0时,自动切换至默认数据源,即在配置文件中定义的dataSource数据源 
  37.      */  
  38.     @Override  
  39.     protected Object determineCurrentLookupKey() {  
  40.         String dataSourceName = DbContextHolder.getDBType();  
  41.         if (dataSourceName == null) {  
  42.             dataSourceName = Constants.DEFAULT_DATA_SOURCE_NAME;  
  43.         } else {  
  44.             this.selectDataSource(dataSourceName);  
  45.         }  
  46.         log.debug("--------> use datasource " + dataSourceName);  
  47.         return dataSourceName;  
  48.     }  
  49.   
  50.     /** 
  51.      * 到数据库中查找名称为dataSourceName的数据源 
  52.      *  
  53.      * @author Geloin 
  54.      * @date Jan 20, 2014 12:15:41 PM 
  55.      * @param dataSourceName 
  56.      */  
  57.     private void selectDataSource(String dataSourceName) {  
  58.         Object sid = DbContextHolder.getDBType();  
  59.         if (Utils.isEmpty(dataSourceName)  
  60.                 || dataSourceName.trim().equals("dataSource")) {  
  61.             DbContextHolder.setDBType("dataSource");  
  62.             return;  
  63.         }  
  64.         Object obj = this._targetDataSources.get(dataSourceName);  
  65.         if (obj != null && sid.equals(dataSourceName)) {  
  66.             return;  
  67.         } else {  
  68.             DataSource dataSource = this.getDataSource(dataSourceName);  
  69.             if (null != dataSource) {  
  70.                 this.setDataSource(dataSourceName, dataSource);  
  71.             }  
  72.         }  
  73.     }  
  74.   
  75.     @Override  
  76.     public void setTargetDataSources(Map<Object, Object> targetDataSources) {  
  77.         this._targetDataSources = targetDataSources;  
  78.         super.setTargetDataSources(this._targetDataSources);  
  79.         afterPropertiesSet();  
  80.     }  
  81.   
  82.     private void addTargetDataSource(String key, DataSource dataSource) {  
  83.         this._targetDataSources.put(key, dataSource);  
  84.         this.setTargetDataSources(this._targetDataSources);  
  85.     }  
  86.   
  87.     private DataSource createDataSource(String driverClassName, String url,  
  88.             String username, String password) {  
  89.         BasicDataSource dataSource = new BasicDataSource();  
  90.         dataSource.setDriverClassName(driverClassName);  
  91.         dataSource.setUrl(url);  
  92.         dataSource.setUsername(username);  
  93.         dataSource.setPassword(password);  
  94.         return dataSource;  
  95.     }  
  96.   
  97.     /** 
  98.      * 到数据库中查询名称为dataSourceName的数据源 
  99.      *  
  100.      * @author Geloin 
  101.      * @date Jan 20, 2014 12:18:12 PM 
  102.      * @param dataSourceName 
  103.      * @return 
  104.      */  
  105.     private DataSource getDataSource(String dataSourceName) {  
  106.         this.selectDataSource(Constants.DEFAULT_DATA_SOURCE_NAME);  
  107.         this.determineCurrentLookupKey();  
  108.         Connection conn = null;  
  109.         try {  
  110.             conn = this.getConnection();  
  111.             StringBuilder builder = new StringBuilder();  
  112.             builder.append("SELECT C_NAME,C_TYPE,C_URL,C_USER_NAME,");  
  113.             builder.append("C_PASSWORD,C_JNDI_NAME,C_DRIVER_CLASS_NAME ");  
  114.             builder.append("FROM IA_DATA_SOURCE WHERE c_name = ?");  
  115.   
  116.             PreparedStatement ps = conn.prepareStatement(builder.toString());  
  117.             ps.setString(1, dataSourceName);  
  118.             ResultSet rs = ps.executeQuery();  
  119.             if (rs.next()) {  
  120.   
  121.                 Integer type = rs.getInt("C_TYPE");  
  122.                 if (Utils.isNotEmpty(type)  
  123.                         && type.intValue() == Constants.DataSourceType.DB  
  124.                                 .intValue()) {  
  125.                     // DB  
  126.                     String url = rs.getString("C_URL");  
  127.                     String userName = rs.getString("C_USER_NAME");  
  128.                     String password = rs.getString("C_PASSWORD");  
  129.                     String driverClassName = rs  
  130.                             .getString("C_DRIVER_CLASS_NAME");  
  131.                     DataSource dataSource = this.createDataSource(  
  132.                             driverClassName, url, userName, password);  
  133.                     return dataSource;  
  134.                 } else {  
  135.                     // JNDI  
  136.                     String jndiName = rs.getString("C_JNDI_NAME");  
  137.   
  138.                     JndiDataSourceLookup jndiLookUp = new JndiDataSourceLookup();  
  139.                     DataSource dataSource = jndiLookUp.getDataSource(jndiName);  
  140.                     return dataSource;  
  141.                 }  
  142.   
  143.             }  
  144.             rs.close();  
  145.             ps.close();  
  146.         } catch (SQLException e) {  
  147.             log.error(e);  
  148.         } finally {  
  149.             try {  
  150.                 conn.close();  
  151.             } catch (SQLException e) {  
  152.                 log.error(e);  
  153.             }  
  154.         }  
  155.         return null;  
  156.     }  
  157.   
  158.     /** 
  159.      * 将已存在的数据源存储到内存中 
  160.      *  
  161.      * @author Geloin 
  162.      * @date Jan 20, 2014 12:24:13 PM 
  163.      * @param dataSourceName 
  164.      * @param dataSource 
  165.      */  
  166.     private void setDataSource(String dataSourceName, DataSource dataSource) {  
  167.         this.addTargetDataSource(dataSourceName, dataSource);  
  168.         DbContextHolder.setDBType(dataSourceName);  
  169.     }  
  170.   
  171. }  

        其中使用的DbContextHolder类的内容如下所示:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  *  
  3.  * @author Geloin 
  4.  * @date Jan 16, 2014 6:08:47 PM 
  5.  */  
  6. package com.gsoft.induasso.datasource;  
  7.   
  8. /** 
  9.  *  
  10.  * @author Geloin 
  11.  * @date Jan 16, 2014 6:08:47 PM 
  12.  */  
  13. public class DbContextHolder {  
  14.   
  15.     private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();  
  16.   
  17.     public static void setDBType(String dbType) {  
  18.         contextHolder.set(dbType);  
  19.     }  
  20.   
  21.     public static String getDBType() {  
  22.         return (String) contextHolder.get();  
  23.     }  
  24.   
  25.     public static void clearDBType() {  
  26.         contextHolder.remove();  
  27.     }  
  28. }  

        文中还涉及到一个Entity类,如下所示:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  *  
  3.  * @author Geloin 
  4.  * @date Jan 17, 2014 10:17:32 AM 
  5.  */  
  6. package com.gsoft.induasso.entity;  
  7.   
  8. import javax.persistence.Column;  
  9. import javax.persistence.Entity;  
  10. import javax.persistence.GeneratedValue;  
  11. import javax.persistence.GenerationType;  
  12. import javax.persistence.Id;  
  13. import javax.persistence.SequenceGenerator;  
  14. import javax.persistence.Table;  
  15.   
  16. import com.gsoft.induasso.constant.Constants;  
  17.   
  18. /** 
  19.  *  
  20.  * @author Geloin 
  21.  * @date Jan 17, 2014 10:17:32 AM 
  22.  */  
  23. @Entity  
  24. @Table(name = "IA_DATA_SOURCE")  
  25. public class GsoftDataSource {  
  26.   
  27.     @Id  
  28.     @SequenceGenerator(name = "IA_DATA_SOURCE_SEQ", sequenceName = "IA_DATA_SOURCE_SEQ", allocationSize = 1)  
  29.     @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "IA_DATA_SOURCE_SEQ")  
  30.     private Long id;  
  31.   
  32.     /** 
  33.      * data source name 
  34.      */  
  35.     @Column(name = "C_NAME", unique = true)  
  36.     private String name;  
  37.   
  38.     /** 
  39.      * data source type, default is database<br /> 
  40.      * {@link Constants.DataSourceType} 
  41.      */  
  42.     @Column(name = "C_TYPE")  
  43.     private Integer type = Constants.DataSourceType.DB.intValue();  
  44.   
  45.     /** 
  46.      * 数据库类型,目前只支持MySql和Oracle<br /> 
  47.      * {@link Constants.DataType} 
  48.      */  
  49.     @Column(name = "C_DATA_TYPE")  
  50.     private Integer dataType = Constants.DataType.ORACLE.intValue();  
  51.   
  52.     @Column(name = "C_URL")  
  53.     private String url;  
  54.   
  55.     @Column(name = "C_USER_NAME")  
  56.     private String userName;  
  57.   
  58.     @Column(name = "C_PASSWORD")  
  59.     private String password;  
  60.   
  61.     @Column(name = "C_JNDI_NAME")  
  62.     private String jndiName;  
  63.   
  64.     @Column(name = "C_DRIVER_CLASS_NAME")  
  65.     private String driverClassName;  
  66.   
  67.     public Long getId() {  
  68.         return id;  
  69.     }  
  70.   
  71.     public void setId(Long id) {  
  72.         this.id = id;  
  73.     }  
  74.   
  75.     public Integer getType() {  
  76.         return type;  
  77.     }  
  78.   
  79.     public void setType(Integer type) {  
  80.         this.type = type;  
  81.     }  
  82.   
  83.     public String getUrl() {  
  84.         return url;  
  85.     }  
  86.   
  87.     public void setUrl(String url) {  
  88.         this.url = url;  
  89.     }  
  90.   
  91.     public String getUserName() {  
  92.         return userName;  
  93.     }  
  94.   
  95.     public void setUserName(String userName) {  
  96.         this.userName = userName;  
  97.     }  
  98.   
  99.     public String getPassword() {  
  100.         return password;  
  101.     }  
  102.   
  103.     public void setPassword(String password) {  
  104.         this.password = password;  
  105.     }  
  106.   
  107.     public String getJndiName() {  
  108.         return jndiName;  
  109.     }  
  110.   
  111.     public void setJndiName(String jndiName) {  
  112.         this.jndiName = jndiName;  
  113.     }  
  114.   
  115.     public String getName() {  
  116.         return name;  
  117.     }  
  118.   
  119.     public void setName(String name) {  
  120.         this.name = name;  
  121.     }  
  122.   
  123.     public String getDriverClassName() {  
  124.         return driverClassName;  
  125.     }  
  126.   
  127.     public void setDriverClassName(String driverClassName) {  
  128.         this.driverClassName = driverClassName;  
  129.     }  
  130.   
  131.     public Integer getDataType() {  
  132.         return dataType;  
  133.     }  
  134.   
  135.     public void setDataType(Integer dataType) {  
  136.         this.dataType = dataType;  
  137.     }  
  138.   
  139. }  

        常量类可忽略。


        在实际的场景中,IA_Data_Source表中保存了多条数据源记录(可以通过增删改查维护),在操作子站点数据时,只需要在每个Service方法中加上以下代码即可:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. DbContextHolder.setDBType("IA_DATA_SOURCE中某个数据源的name属性的值");  
0 0