`

j2ee动态数据源使用方法

阅读更多

情况:

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

 

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

 

解决方案:

 

数据库datasource,需要继承AbstractRoutingDataSource ,在spring包里面。

/**
 * <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配置文件:

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如下:

/**
 * <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放入线程变量中。

 

自己定义一个数据库事务管理器:

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类的

方法:

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

 

然后是:

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;
	}

 里面会用到方法:

Object lookupKey = determineCurrentLookupKey();

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

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

 

 

0
1
分享到:
评论
2 楼 smallbee 2011-08-04  
sijuven 写道
您好,我想问一下,你们的数据源是有后台可以维护的,这些信息是如何在应用启动的时候加载 进来的呢,比如你现在运行过程中,我在后台添加了一条数据源信息。

不好意思,没有看到你提问。系统启动的时候,加载spring配置文件,所以都会放在bean里面,所以如果你要新增数据源,需要停止服务,然后更新配置文件,重新启动后台。
1 楼 sijuven 2011-07-12  
您好,我想问一下,你们的数据源是有后台可以维护的,这些信息是如何在应用启动的时候加载 进来的呢,比如你现在运行过程中,我在后台添加了一条数据源信息。

相关推荐

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

    本文介绍了用JNDI定义Oracle数据源的方法。

    J2EE二手市场源代码

    自己做的一个小东西 MVC模式练习 数据库用的ACCESS 需要配置数据源为 tiaozao2.0

    基于J2EE的介绍

    •JCA(Java连接器体系结构):一种技术,用于外部数据源和传统的J2EE组件提供的功能。 •JTA,JTS(Java Transaction API和Java事务服务):指定接口的异构分布式交易。 •RMI/ IIOP(远程过程调用/因特网ORB间协议...

    基于JAVA-COM Bridge与J2EE连接器的COM数据源信息获取.pdf

    基于JAVA-COM Bridge与J2EE连接器的COM数据源信息获取.pdf

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

    博文链接:https://cui.iteye.com/blog/110617

    基于J2EE的网上商城源代码+数据库(sql)

    基于J2EE的网上商城项目,代码齐全,功能齐全,界面美观,有数据库sql,还有文档说明。是一个很好的综合实训项目。

    J2EE之DAO设计模式

    暴露给客户端的DAO接口在低层数据源的实现发生改变时并不会随着改变,所以这种设计模式使得DAO可以适应不同的数据储存方式类型而不影响客户端和商业组件.最主要的, DAO还在组件和数据源之间扮演着协调者的角色. DAO...

    J2EE服务器中如何配置DataSource

    本文根据一个实际的基于SSH2架构的WEB应用程序来配置J2EE服务器的数据源,开发测试环境采用TOMCAT6+MySQL, 集成测试环境采用WebSphere6.1 + DB2/MySQL. 详细的图文资料描述如何配置WebSphere6.1下的DB2和My SQL数据...

    基于J2EE 客户管理系统毕业设计

    中文摘要 JAVA语言是目前Internet上大型的WEB应用程序开发时使用的最热门的编程语言,本文以“摩托罗拉客户管理模块”的制作过程为例,以...关键字:JAVA、 Ext、 SQLServer、 数据源、 框架、 JavaBean、J2EE、MVC

    基于Ajax+J2EE的ERP系统源码

    基于j2ee、ajax、mysql开发的ERP系统,带有完整的系统源代码和数据脚本,对有志于研究j2ee技术和erp原理的同志有帮助。

    J2EE经典实例详解 <4>

    Duke在线银行实例是美国Sun Microsystems公司在其《J2EE学习指南》中使用的一个完整实例,该实例涵盖了Java的最主要的核心技术,其规模大小适中。 &lt;br&gt;本书紧紧围绕Duke应用实例,进行了由远及近的全面介绍和自底...

    was图文教学-数据源配置

    一个手把手以图文的形式介绍websphere中数据源的配置,是was初学者很好的教程

    论文研究-基于XML与J2EE技术的数据交换中心的设计与实现.pdf

    为实现在异质异源数据库间的数据交换,使用户可以透明地访问数据,提出一种建立数据交换中心的解决方案。在该数据交换中心的构建中,综合采用了XML,J2EE,XSLT等技术。通过使用XML作为数据的载体,运用XSLT样式表对...

    计算机外文翻译-文献综述(j2ee)本科学位.doc

    这种框架需要考虑大量的系统服务和应用组件的配置,例如 JDBC 数据源、消息队列和资源适配器等。 本文首先介绍了基于组件的企业应用开发的显著增加和分布式环境下的挑战,然后讨论了垂直分割和垂直负荷的概念,并...

    J2EE经典实例详解 <2>

    Duke在线银行实例是美国Sun Microsystems公司在其《J2EE学习指南》中使用的一个完整实例,该实例涵盖了Java的最主要的核心技术,其规模大小适中。 &lt;br&gt;本书紧紧围绕Duke应用实例,进行了由远及近的全面介绍和自底...

    基于J2EE的交友社区网站开发

    下载就能用,基于J2EE的交友社区网站开发,包含源代码和文档,使用Eclipse开发,采用SSH中的Struts+hibernate,数据采用的是MySQL。

    J2EE应用开发详解

    118 8.3.5 Struts2配置文件 119 8.4 Action的配置方式 121 8.4.1 动态方法调用 121 8.4.2 设置action元素的method属性 122 8.4.3 使用通配符配置action 122 8.4.4 默认action 123 8.5 拦截器Interceptor 123 8.5.1 ...

    J2EE网上银行系统

    J2EE 大作业,包括java源代码和完整的文档 该项目是由CodeRunner项目组提出建议,由CodeRunner项目组开发的一款B/S架构的网上银行网站,用Internet技术搭建一个虚拟银行柜台,向客户提供传统金融服务项目,使客户...

    J2EE项目开发Excel导入导出操作组件源代码(附带说明文档)

    J2EE项目开发Excel数据导入导出操作组件源代码(附带说明文档),非常实用!

    轻量级J2EE企业应用实战(第3版)

    《轻量级java ee企业应用实战(第3版)—struts 2+spring 3+hibernate整合开发》 第1章 java ee应用和开发环境 1 1.1 java ee应用概述 2 ...1.3.5 配置tomcat的数据源 13 1.4 eclipse的安装和使用 15

Global site tag (gtag.js) - Google Analytics