-
spring-boot记录sql探索
目标记录每次请求内的http、es、mysql耗时,本篇讨论mysql部分
为什么说要探索,这不是很简单的事么?但是能满足以下几点么?
- 能记录limit等参数
- 能将参数和sql写一起,能直接使用
- 能记录耗时
- 能计数累加,统计一次请求中sql执行的总数和总耗时
spring原生能力
|
logging.level.org.hibernate.SQL=debug |
|
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=trace |
通过上面两条配置。
- ✔️可以显示sql.
- ❌不能和参数一行显示
- ❌不能显示limit参数
- ❌不能计数和记录耗时
|
2021-02-23 19:35:42.932 DEBUG 97586 --- [ restartedMain] org.hibernate.SQL : select admin0_.id as id1_0_, admin0_.create_time as create_t2_0_, admin0_.modify_time as modify_t3_0_, admin0_.email as email4_0_, admin0_.password as password5_0_, admin0_.status as status6_0_, admin0_.username as username7_0_ from admin admin0_ where admin0_.username=? |
|
2021-02-23 19:35:42.949 TRACE 97586 --- [ restartedMain] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [root] |
原生log+org.hibernate.EmptyInterceptor
org.hibernate.EmptyInterceptor
提供钩子,hibernate本身提供entity的curd钩子。重写EmptyInterceptor
方法,可以实现计数。但是onPrepareStatement
方法只是装配sql前的事件,而且不是完整的sql。
- ✔️ 可以显示sql
- ❌ 不能和参数一行显示
- ❌ 不能显示limit参数
- ✔️ 能计数
- ❌ 不能记录耗时
|
spring.jpa.properties.hibernate.ejb.interceptor=com.vison.itdoc.config.HibernateInterceptor |
|
public class HibernateInterceptor extends EmptyInterceptor { |
|
|
|
|
|
public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { |
|
// Log.info("onload...", entity) |
|
return true; |
|
} |
|
|
|
|
|
public String onPrepareStatement(String string) { |
|
// count++ |
|
return INSTANCE.onPrepareStatement(string); |
|
} |
|
|
|
|
|
public void afterTransactionCompletion(Transaction t) { |
|
INSTANCE.afterTransactionCompletion(t); |
|
Log.info("after trans complete", t); |
|
} |
|
|
|
} |
log4jdbc
log4jdbc能很好的解决sql完整显示和记录耗时的问题
|
2021-02-23 19:59:13.709 INFO 97586 --- [nio-8081-exec-1] jdbc.sqltiming : select posts0_.id as id1_2_, posts0_.create_time as create_t2_2_, posts0_.modify_time as modify_t3_2_, |
|
posts0_.content as content4_2_, posts0_.title as title5_2_ from posts posts0_ where 1=1 order |
|
by posts0_.id asc limit 10 ; |
|
{executed in 1 msec} |
还能够定义超过1定时间的执行sql记录为error类型。
|
<dependency> |
|
<groupId>com.googlecode.log4jdbc</groupId> |
|
<artifactId>log4jdbc</artifactId> |
|
<version>1.2</version> |
|
<scope>runtime</scope> |
|
</dependency> |
|
|
spring.datasource.driver-class-name: net.sf.log4jdbc.DriverSpy |
|
#使用log4jdbc后mysql的url |
|
spring.datasource.url=jdbc:log4jdbc:mysql://localhost:3306/xxxx?useUnicode=true&characterEncoding=UTF-8 |
|
#使用log4jdbc后oracle的url |
|
#spring.datasource.url: jdbc:log4jdbc:oracle:thin:@127.0.0.1:1521:orcl |
|
注意需要添加spring.datasource.driver-class-name
和更改 spring.datasource.url
将jdbc改为 jdbc:log4jdbc
log4jdbc.properties可以定义更多配置
|
#配置为需要记录的包或类匹配路径 |
|
#log4jdbc.debug.stack.prefix=com.drp |
|
#log4jdbc加载的drivers (驱动名) |
|
#log4jdbc.drivers=oracle.jdbc.OracleDriver |
|
log4jdbc.auto.load.popular.drivers=true |
|
#在日志中显示warn警告 |
|
log4jdbc.statement.warn=true |
|
#毫秒值.执行时间超过该值的SQL语句将被记录为warn级别. |
|
log4jdbc.sqltiming.warn.threshold=2000 |
|
#毫秒值.执行时间超过该值的SQL语句将被记录为error级别. |
|
log4jdbc.sqltiming.error.threshold=3000 |
|
#是把boolean记录为 'true'/'false' 还是 1/0. 默认设置为false,不启用,为了移植性. |
|
#log4jdbc.dump.booleanastruefalse=true |
|
#输出的sql,一行最大的字符数,默认90. 以后新版可能为0 |
|
#log4jdbc.dump.sql.maxlinelength=90 |
|
#如果在调试模式下转储,则转储整个堆栈跟踪 默认false |
|
log4jdbc.dump.fulldebugstacktrace=false |
|
|
|
#是否记录某些类型的语句,默认true |
|
log4jdbc.dump.sql.select=true |
|
log4jdbc.dump.sql.insert=true |
|
log4jdbc.dump.sql.delete=true |
|
log4jdbc.dump.sql.update=true |
|
log4jdbc.dump.sql.create=true |
|
|
|
#输出sql末尾处加入分号,默认false |
|
log4jdbc.dump.sql.addsemicolon=true |
|
|
|
#将此设置为false以不修剪已记录的SQL |
|
log4jdbc.trim.sql=true |
|
#将此设置为false不删除额外的空行 |
|
log4jdbc.trim.sql.extrablanklines=true |
|
|
|
#log4jdbc.suppress.generated.keys.exception=false |
|
|
|
- ✔️ 可以显示sql
- ✔️ 不能和参数一起显示
- ✔️ 不能显示limit参数
- ❌ 能计数
- ✔️ 能记录单个sql耗时
- ❌ 不能统计总耗时
不足的是,单纯log4jdbc并不能满足所有。理论上log4jdbc+org.hibernate.EmptyInterceptor可以满足需求了
P6Spy
测试完毕,发现P6Spy目前最能满足需求:
- ✔️ 可以显示sql
- ✔️ 不能和参数一起显示
- ✔️ 不能显示limit参数
- ✔️ 能计数
- ✔️ 不能记录耗时
- ✔️ 支持curd事件前后钩子,钩子参数返回sql和执行耗时及异常信息
最新更新
python爬虫及其可视化
使用python爬取豆瓣电影短评评论内容
nodejs爬虫
Python正则表达式完全指南
爬取豆瓣Top250图书数据
shp 地图文件批量添加字段
爬虫小试牛刀(爬取学校通知公告)
【python基础】函数-初识函数
【python基础】函数-返回值
HTTP请求:requests模块基础使用必知必会
SQL SERVER中递归
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
uniapp/H5 获取手机桌面壁纸 (静态壁纸)
[前端] DNS解析与优化
为什么在js中需要添加addEventListener()?
JS模块化系统
js通过Object.defineProperty() 定义和控制对象
这是目前我见过最好的跨域解决方案!
减少回流与重绘
减少回流与重绘
如何使用KrpanoToolJS在浏览器切图
performance.now() 与 Date.now() 对比