`
chenhua_1984
  • 浏览: 1253863 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

使用Java代理来实现对JDBC驱动的一些扩展

    博客分类:
  • java
阅读更多

     

      我们都知道,编程语言在与数据库打交道的时候,中间需要一个Driver,这个驱动,一般由数据库厂商开发提供,根据不同的数据库版本而提供不同版本的驱动,Oracle数据库对Java的版本就有好几种:比如Ojdbc14.jar等,这些驱动,通常实现了有JSR定义好的接口规范,比如Java.sql.connection,java.sql.Driver;接口等。

     

public interface Connection  extends Wrapper {
    Statement createStatement() throws SQLException;
    PreparedStatement prepareStatement(String sql)throws SQLException;	
    CallableStatement prepareCall(String sql) throws SQLException;

     在Java通过JDBC驱动与Oracle数据的交互过程中,有没有办法在驱动层面实现对Sql语句执行过程的监控呢?利用Java的动态代理即可以实现。Java开发包中包含了对动态代理的支持,但是其实现只支持对接口的的实现。 其实现主要通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。我们知道,通过动态代理,可以拦截请求(或则说对请求做增强),那么我们通过这一点可以对JDBC的执行过程做增强处理。

   

    JDBC在和Oracle交互的过程,主要经过以下几个步骤:

    首先获取连接 getConnection,获取连接的过程需要注册驱动

   

public class DriverLoggingProxy implements Driver {

	static final Logger logger = LoggerFactory.getLogger(DriverLoggingProxy.class);

	static final String urlPrefix = "jdbc:jdbcdslog:";

	static final String targetDriverParameter = "targetDriver";
	private static DriverLoggingProxy defaultDriver;
	

	static {
		try {
		    if(defaultDriver == null)
		    {
                 defaultDriver = new DriverLoggingProxy();
     		     DriverManager.registerDriver(defaultDriver);
		}
		}catch (Exception exception) {
		}
	}

 

    接着:构造Statement对象

 

    然后:执行Execute

 

    最后:获取结果,提交事务(Commit)

 

    大致可可以分为这四个步骤

         我们知道JDBC对数据库的处理构造Statement对象主要提供了三种接口方式:如下

   

createStatement()   //最容用的方式,缺点容易被注入攻击

prepareStatement(String sql) //防止SQL注入

prepareCall(String sql)  //存储过程调用

 

      利用Java的动态代理,我们则可以实现在Execute的前后增加业务逻辑,来实现我们对Sql语句的执行时间的一个监控(也就是Sql的性能监控)

       

public class StatementLoggingProxy implements InvocationHandler {

	static final Logger logger = LoggerFactory.getLogger(StatementLoggingProxy.class);

	Object targetStatement = null;

	static List executeMethods = Arrays.asList(new String[] { 
			"execute", "executeQuery", "executeUpdate","executeBatch" });
	


	public StatementLoggingProxy(Object statement) {
		targetStatement = statement;
	}

	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		Object r = null;
		try {
			boolean toLog = (StatementLogger.logger.isInfoEnabled() || SlowQueryLogger.logger
					.isInfoEnabled())
					&& executeMethods.contains(method.getName());
			long t1 = 0;
			if (toLog)
				t1 = System.currentTimeMillis();
			
			
			if(executeMethods.contains(method.getName())){
				ConnectionAspectFacade.createStatementAdvice(this.targetStatement);
			}
			
			r = method.invoke(targetStatement, args);
			if (toLog) {
				long t2 = System.currentTimeMillis();
				StringBuffer sb = LogUtils.createLogEntry(method, args[0],
						null, null);
				long time = t2 - t1;
				String logEntry = sb.append(" ").append(time).append(" ms.")
						.toString();
				StatementLogger.logger.info(logEntry);
				if (time >= ConfigurationParameters.slowQueryThreshold)
					SlowQueryLogger.logger.info(logEntry);
			}
			return r;
		} catch (Throwable t) {
			LogUtils.handleException(t, StatementLogger.logger, LogUtils
					.createLogEntry(method, args[0], null, null));
		}
	
			
		
				
		return r;
	}
	

 

       同时,也可以利用Oracle的Identifi_context来实现Sql语句与执行的终端绑定,在Oracle的Session列表里有一个Identifi字段,可以通过JDBC 驱动的setEndToEndMetrics 方法来设置值(浏览器端的身份信息),这样,任何一个SQL语句执行的时候,Oracle都能知道是哪个终端发起的,那么我要怎么才知道浏览器端的人是谁呢?这是一个身份识别的问题,利用Filter就可以实现这一点。

 

      我们BS程序通常都是有Session的,用来存放登录的身份相关信息

在向Server发起Http请求的时候,身份信息是要被验证的,当我们的身份信息在登录的时候,验证成功,那么身份信息会被保存到Session里面,我们在Web程序最前面加入一个Filter(拦截器),拦截Http请求,当有请求发生的时候,首先我们可以拿到他的Ip地址

  

	HttpServletRequest request = (HttpServletRequest) req;
		String ip = request.getHeader("X-Forwarded-For");
		if (ip != null && !"".equals(ip)) {
			logger.debug("origin ip:" + ip + " will replace proxy ip:"
					+ req.getRemoteAddr());
		} else {
			ip = req.getRemoteAddr();
		}
		return ip;

  

X-Forwarded-For //这里指硬件的负载均衡(F5,Array,RedWare等)需要配置的参数

   

    而后,我们可以采用Session迭代的方式,迭代出当前的Session信息,通过Session信息枚举的分析,分析出Session的结构(这个步骤需要测试阶段完成),然后记录下来,在每次Http请求的过程中,根据分析到的Session结构去获取Session信息(这里我们其实主要要取的是Username),加上前面的Ip地址,这样就可以确定到底是哪个”人“了。

    

    拿到人以后,需要送去给后台的JDBC驱动,以至于让Oracle也知道这条SQL语句是谁执行的,那么我们可以通过    ThreadLocal identityContexts = new ThreadLocal() 绑定实现,把身份信息通过ThreadLocal与后台Http请求绑定,通过

 

setEndToEndMetrics方法传递给Jdbc的Connection

  

      示例代码:

 

public class GenericLoggingProxy implements InvocationHandler {

	static final Logger logger = LoggerFactory.getLogger(GenericLoggingProxy.class);

	static List methodsBlackList = Arrays.asList(new String[] {
			"getAutoCommit", "getCatalog", "getTypeMap", "clearWarnings",
			"setAutoCommit", "getFetchSize", "setFetchSize", "commit" });

	private Object target = null;

	public GenericLoggingProxy(Object target) {
		this.target = target;
	}

	public GenericLoggingProxy(Object target, String sql) {
		this.target = target;
	}

	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		Object r=null;
		try {
			r = method.invoke(target, args);
			if ("getConnection".equals(method.getName())) {
				r = (Connection) ConnectionLoggingProxy.wrap((Connection) r);
				return r;
			}
			if (method.getName().equals("prepareCall")
					|| method.getName().equals("prepareStatement"))
				r = wrap(r, (String) args[0]);
			else
				r = wrap(r, null);
			return r;
		} catch (Throwable t) {
			LogUtils.handleException(t, ConnectionLogger.logger, LogUtils
					.createLogEntry(method, null, null, null));
		}
		
		return r;
	}

 

	if (r instanceof CallableStatement)
			return wrapByCallableStatementProxy(r, sql);
		if (r instanceof PreparedStatement)
			return wrapByPreparedStatementProxy(r, sql);
		if (r instanceof Statement)
			return wrapByStatementProxy(r);
//		if (r instanceof ResultSet)
//			return ResultSetLoggingProxy.wrapByResultSetProxy((ResultSet) r);
		return r;

    

写道
JDBC supports four end-to-end metrics, all of which are set on a per-connection basis:

Action

This is a String

ClientId

This is a String

ExecutionContextId

This is a combination of String and short SequenceNumber)

Module

This is a String
	String metrics[] = new String[OracleConnection.END_TO_END_STATE_INDEX_MAX];
		String clientIdentifier = identityContext.getClientIdentifier(true);
		metrics[OracleConnection.END_TO_END_CLIENTID_INDEX] = clientIdentifier;
		metrics[OracleConnection.END_TO_END_ACTION_INDEX] = identityContext
				.getAction();
//		metrics[OracleConnection.END_TO_END_MODULE_INDEX] = identityContext
//				.getModule();
		Statement st=null;
		OracleConnection conns =null;
		try {
			if (logger.isDebugEnabled()) {
				logger.debug("call setEndToEndMetrics with [clientId="
						+ metrics[OracleConnection.END_TO_END_CLIENTID_INDEX]
						+ "]");
			}
//			OracleConnection conn = (OracleConnection) adviceContext
//					.getCurrentConnection();
			st=(Statement)statement;
			conns = (OracleConnection)st.getConnection();
			conns.setEndToEndMetrics(metrics, (short) 0);

 

     在Oracle段,可以 利用Oracle的VPD技术,可以实现WEB程序的审计系统

     

     

 

分享到:
评论

相关推荐

    greenplum数据库jdbc驱动下载

    JDBC驱动是Java程序与数据库之间的一座桥梁,它实现了Java的JDBC API,使得Java代码可以调用数据库的特定功能。对于Greenplum,"greenplum-jdbc-5.1.4.jar"提供了以下关键功能: 1. **连接管理**:创建、管理和关闭...

    数据库JDBC驱动程序包

    数据库JDBC驱动程序包是一个非常重要的组件,尤其对于Java Web开发者而言,它是连接各种数据库的基础。JDBC(Java Database Connectivity)是Java编程语言中的一个标准API,它允许Java应用程序与各种类型的数据库...

    informix jdbc驱动

    Informix JDBC驱动程序实现了这一接口,使得Java开发者可以利用Java语言访问Informix数据库,进行数据查询、更新、插入和删除等操作。 标题中的“informix jdbc驱动”指的是专门针对Informix数据库的JDBC驱动程序,...

    kingbaseV8 jdbc 驱动

    KingbaseV8 JDBC驱动是连接Kingbase数据库管理系统与Java应用程序之间的桥梁,允许Java开发者通过标准的Java Database Connectivity (JDBC) API来访问和操作KingbaseV8数据库。JDBC是Oracle公司提出的用于在Java程序...

    Oracle 9i、10g、11g通用jdbc驱动包

    它提供了一组接口和类,使得Java程序员可以使用Java语言来编写数据库应用程序,实现数据的增删查改操作。 2. Oracle JDBC驱动类型: - Type 1( Thin Driver):轻量级驱动,纯Java实现,无需Oracle客户端,直接...

    sqlserver 2008 jdbc 驱动包

    通过SQLServer 2008 JDBC驱动包,Java开发者可以充分利用SQL Server 2008的强大功能,创建健壮的、可扩展的数据库应用。同时,驱动还支持一些高级特性,如批处理、游标、存储过程调用、事务隔离级别设置等,以满足...

    神通数据库JDBC驱动包

    JDBC(Java Database Connectivity)驱动则是连接Java应用程序和各种数据库的桥梁,神通数据库的JDBC驱动包(oscarJDBC.jar)正是为了实现这一目的而提供的。 首先,让我们深入了解一下JDBC。JDBC是Java平台上的一...

    hive jdbc驱动 2.5.15 及 2.6.1两个版本

    Hive JDBC驱动是连接Hadoop生态系统中的Hive数据仓库的重要桥梁,它允许用户通过Java数据库连接(JDBC)标准来访问Hive。在Hive 2.5.15和2.6.1这两个版本中,都包含了对Hive查询语言(HQL)的支持以及对大数据处理的...

    jdbc连接access数据库的驱动jar包

    - "连接数据库驱动":即JDBC驱动,是实现JDBC接口的类库,用于在Java应用程序和特定类型的数据库之间建立通信桥梁。 在压缩包的“lib”目录下,可能包含的就是这个JDBC驱动的JAR文件。通常,将这个JAR添加到Java...

    mssqlserver2008的JDBC驱动包 for linux

    3. `mssql-jdbc.jar`:主JDBC驱动程序的Java归档(JAR)文件,用于在Java应用中导入并使用。 4. `mssql-jdbc_auth-3.0.x.x-x-x-x-linux.jar`:用于Linux的SQL Server身份验证扩展,支持NTLM或Kerberos认证。 5. `...

    informix jdbc 驱动包

    Informix JDBC驱动包是连接Java应用程序与Informix数据库的关键组件,它遵循Java Database Connectivity (JDBC) API标准,使得Java开发者能够通过编写Java代码来访问和操作Informix数据库。本篇将详细介绍Informix ...

    jdbc驱动程序

    在“标签”中提到的“源码”可能是指这些JDBC驱动的源代码,开发者可以研究它们的工作原理,甚至对其进行修改或扩展以满足特定需求。而“工具”可能指的是使用JDBC驱动进行数据库操作的一些辅助工具或框架,例如...

    SQL2000的jdbc驱动包

    2. `mssqlserver.jar`:这是针对SQL Server特定的JDBC驱动扩展,包含了一些针对SQL Server特定特性的实现,例如TDS(Tabular Data Stream)协议的支持,该协议是SQL Server用来传输数据的标准。这个文件让Java应用...

    java jdbc 需要包

    2. `mysql-connector-java-5.1.21-bin.jar`: 这是MySQL数据库的JDBC驱动,用于建立Java应用程序与MySQL数据库之间的连接。 3. `spring-beans-3.2.0.M1.jar`: 包含了Spring对bean的管理和配置,是Spring框架的重要...

    DB2 JDBC驱动

    JDBC驱动程序是Java程序员与各种数据库进行交互的桥梁,它允许Java应用程序通过标准的Java API来访问数据库。在本压缩包中,包含了四个重要的文件,分别是db2jcc.jar、db2java.jar、db2jcc_javax.jar和db2jcc_...

    SQL Server 2000 JDBC驱动的三个Jar包

    总结来说,SQL Server 2000的JDBC驱动由msbase.jar、mssqlserver.jar和msutil.jar这三部分组成,它们共同构成了一个完整的JDBC驱动程序,允许Java应用程序无缝地与SQL Server 2000进行数据交互。了解和正确使用这些...

    JSP连接mysql:JDBC驱动5.1

    JDBC驱动5.1版引入了一些新特性,例如更好的性能优化、对InnoDB存储引擎的支持增强以及对大型结果集处理的改进。此外,还支持MySQL的高级特性,如存储过程、事务处理和预编译的SQL语句。 在JSP中,你可能将这些...

    java jdbc4.1驱动

    总的来说,Java JDBC 4.1驱动为Java开发者提供了一套强大且完善的工具,以适应不断发展的SQL Server数据库需求。通过理解并充分利用这些特性,开发者可以编写出更高效、更稳定的数据库应用。在实际开发中,正确配置...

    jdbc-driver-rpc,自实现的jdbc驱动,用于集成进mysql等框架.zip

    总结一下,"jdbc-driver-rpc"是一个创新的解决方案,它使用HTTP和JSON实现了自定义的JDBC驱动,便于集成到如MySQL这样的数据库框架中。这种设计提供了更高的灵活性,但也带来了安全和性能方面的考虑。在决定使用前,...

    sql server2000的jdbc驱动包

    SQL Server 2000 JDBC驱动包是Java开发者与Microsoft SQL Server 2000数据库进行交互的重要工具。JDBC(Java Database Connectivity)是Java语言中用于与各种数据库建立连接的API,它允许Java应用程序通过Java代码...

Global site tag (gtag.js) - Google Analytics