背景

你是否和我一样一直有个疑问,如何查看系统执行过的所有sql,之前做oracle中间件实施的时候,由于oracle产品不开放源代码,也不公开表结构设计,因此一个功能涉及到哪些表,具体表里存的数据代表什么除了oracle没人知道,如果了解哪些功能涉及到哪些表,表里的数据都分表对应哪些功能更有助于我们对产品的理解和对问题的解决。

之前曾经想过通过oracle系统表v$sql进行监控,但效果并不理想,如果用过druid连接池应该知道,druid主打的功能就是sql监控(一个数据库连接池竟然干监控的活,有点不务正业),druid的原理是提供了一套jdbc的接口,自然所有的sql都要通过它来执行,这个也给了我们一个思路,如果可以监控jdbc相关方法的执行,不就可以实现以上目的,有了arthas之后,这个事就变得很简单。

jdbc

我们知道,jdbc中负责执行sql的是PreparedStatementStatement,PreparedStatement用于参数绑定,有防注入,避免硬解析等好处,Statement执行纯sql,因此正式环境一般推荐使用PreparedStatement进行sql操作,PreparedStatement通过Connection.prepareStatement(String sql)方法创建,所以我们监控该方法就能得到sql,arthas中watch命令可以监控方法的执行,那问题来了,Connection只是jdbc的接口,并非最终的实现类,我们需要监控的是实现类,并非接口,通过查看oracle jdbc驱动包不难发现,oracle jdbc对于Connection的实现类是oracle.jdbc.OracleConnectionWrapper,执行下面命令开始监控。

[arthas@30318]$ watch oracle.jdbc.OracleConnectionWrapper prepareStatement "{params[0]}" -x 2 -n 999999
Press Q or Ctrl+C to abort.
Affect(class-cnt:9 , method-cnt:21) cost in 7882 ms.

这里对这条命令简单解释

  • “{params[0]}”表示输入方法的第一个参数,在本例中,prepareStatement的第一个参数也是唯一一个参数就是执行的sql
PreparedStatement prepareStatement(String sql)
  • -x 2表示结果的遍历深度,默认是1,什么意思呢,有些参数可能是对象,那么这个参数表示展开对象的深度,有可能里面对象套对象。
  • -n 999999表示输出结果数,默认是100,也就是该方法被调用查过该次数后,命令就退出,如果希望能够持续的进行监控,这里可以设置大一点。

现在我们调用接口,可以在屏幕上里面打印出sql

但结果太多,屏幕显示不下,又不好分析怎么办?可以把结果保存到本地文件夹,artahs文件保存功能默认是关闭的,如果需要开启,需要执行以下命令。

$ options save-result true
 NAME         BEFORE-VALUE  AFTER-VALUE
----------------------------------------
 save-result  false         true
Affect(row-cnt:1) cost in 3 ms.

结果会异步保存在:{user.home}/logs/arthas-cache/result.log。看到日志里满屏幕的sql,就像是收获了满满果实的果农,异常的满足。通过研究产品的sql,更有助于你理解功能,排查问题。

Trackback

no comment untill now

Add your comment now