您的位置:首页 > 编程语言 > Java开发

Java动态代理监控JDBC连接和执行SQL的脚本参数

2019-01-14 15:05 721 查看

前言

Java后他开发无法避免的需要和数据库打交道,我们希望能够能够再数据库中打印每一次JDBC的连接URL信息,执行的SQL脚本和传递的参数信息,本文仅仅实现了一个简单的Demo,算是简单的一个思路。

JDBC的执行流程

Java访问数据库的框架有很多,类似Mybatis,JPA等,熟悉Java开发的童鞋应该都知道不论使用何种框架,都无法避免的需要mysql-connector-java这个jar包(访问MySQL数据库,其他的数据库需要加入对应厂商的)。Java本身提供了java.sql.*包,这个包里面仅仅提供了访问数据库的接口,例如public interface Connection extends Wrapper, AutoCloseable,具体的实现类再不同的驱动程序中。

// jdbc访问数据库的代码
//1.加载驱动程序
Class.forName("com.mysql.jdbc.Driver");
//2.获得数据库链接
Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
//3.通过数据库的连接操作数据库,实现增删改查(使用PreparedStatement 类)
PreparedStatement ps = conn.prepareStatement("select 1");
//4、设置参数
// ps.setLong();
//5、获取查询的结果ResultSet
ResultSet resultSet = ps.executeQuery();

整个方式数据库的流程大概分为6步骤:
1、加载驱动程序
2、获得数据库链接
3、通过数据库的连接操作数据库,实现增删改查(使用PreparedStatement 类)
4、设置参数,如果需要的话
5、获取查询的结果ResultSet
6、处理查询结果
jdbc访问数据库的流程大概就是上述的六个过程,那么我们需要从哪里去动态代理?代理Connection和PreparedStatement这两个给,Connection类里面获取数据库连接信息和SQL语句,PreparedStatement中获取设置的参数

JdbcProxy类

package com.parallel.stomp.test.jdbc.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.*;

/**
* @author rewnei2
* @version v0.1 2019/1/14 10:37
*/
public class JdbcProxy {
public Connection getConnection() throws ClassNotFoundException, SQLException {
String URL = "jdbc:mysql://192.168.94.38:3306/dp";
String USER = "root";
String PASSWORD = "root";
//1.加载驱动程序
Class.forName("com.mysql.jdbc.Driver");
//2.获得数据库链接
Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
return conn;
//3.通过数据库的连接操作数据库,实现增删改查(使用Statement类)
//PreparedStatement ps = conn.prepareStatement("select 1");
//Object obj = ps.executeQuery();
}

public Connection proxyConnection(Connection connection) {
Object obj = Proxy.newProxyInstance(JdbcProxy.class.getClassLoader(), new Class[]{Connection.class}, new ConnectionProxyHandler(connection));
return (Connection) obj;
}

class ConnectionProxyHandler implements InvocationHandler {
private Connection connection;

public ConnectionProxyHandler(Connection connection) {
this.connection = connection;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
boolean targetMethodFlag = false;
Object result = null;
if ("prepareStatement".equals(method.getName())) {
targetMethodFlag = true;
}
if (targetMethodFlag) {
System.out.println("database=" + connection.getCatalog() + ",url=" + connection.getMetaData().getURL());
System.out.println(String.format("开始执行时间%s,执行sql语句%s", System.currentTimeMillis(), args[0]));
result = method.invoke(connection, args);
System.out.println(String.format("结束执行时间%s,执行sql语句%s", System.currentTimeMillis(), args[0]));
}
if (targetMethodFlag && result instanceof PreparedStatement) {
PreparedStatement ps = (PreparedStatement) result;
result = proxyPreparedStatement(ps);
}
return result;
}

}

public PreparedStatement proxyPreparedStatement(final PreparedStatement statement) {
Object c = Proxy.newProxyInstance(JdbcProxy.class.getClassLoader()
, new Class[]{PreparedStatement.class}, new PreparedStatementHandler(statement));
return (PreparedStatement) c;
}

/**
* PreparedStatement 代理处理
*/
public class PreparedStatementHandler implements InvocationHandler {
private final PreparedStatement statement;

public PreparedStatementHandler(PreparedStatement statement) {
this.statement = statement;
}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("setLong")) {
System.out.println("position:" + args[0] + "value:" + args[1]);
}
Object result = method.invoke(statement, args);
return result;
}
}

}

测试类

public class TestMain {

public static void main(String[] args) throws SQLException, ClassNotFoundException {
JdbcProxy jdbcProxy = new JdbcProxy();
Connection connection = jdbcProxy.getConnection();
Connection connectionProxy = jdbcProxy.proxyConnection(connection);
PreparedStatement ps = connectionProxy.prepareStatement("SELECT * FROM client WHERE id=?");
ps.setLong(1, 141);
ResultSet resultSet = ps.executeQuery();
System.out.println(resultSet);
while (resultSet.next()) {
System.out.println(resultSet.getLong(1));
}
/* byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{PreparedStatement.class});
String path = "D:/codes/Stomp_Communicate/src/main/java/com/parallel/stomp/test/jdbc/proxy/JdbcProxy.class";
try (FileOutputStream fos = new FileOutputStream(path)) {
fos.write(classFile);
fos.flush();
System.out.println("代理类class文件写入成功");
} catch (Exception e) {
System.out.println("写文件错误");
}*/

}
}

运行结果

database=xxxx,url=jdbc:mysql://127.0.0.1:3306/xxxx
开始执行时间1547449304808,执行sql语句SELECT * FROM client WHERE id=?
结束执行时间1547449304838,执行sql语句SELECT * FROM client WHERE id=?
position:1value:141
......
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: