JPA的SQL语句及参数展示

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 无意间遇到的问题,调试业务代码用到的ORM框架是JPA,但是只有预执行sql,没有相关的Parameter参数。网上google、度娘、说的都是驴唇不对马嘴,整理下做一下备忘。

JPA的执行流程

大致整理下JPA的执行流程,中间省略了很多过程。

IMG

核心的类方法

  • org.hibernate.sql.results.jdbc.internal.DeferredResultSetAccess#executeQuery
private void executeQuery() {
    final LogicalConnectionImplementor logicalConnection = getPersistenceContext().getJdbcCoordinator().getLogicalConnection();
    final QueryOptions queryOptions = executionContext.getQueryOptions();

    try {
      //这个地方是展示SQL的地方。trace级别
      LOG.tracef( "Executing query to retrieve ResultSet : %s", finalSql );
      // prepare the query
      preparedStatement = statementCreator.apply( finalSql );

        
      // set options
      .....这部分代码省略

      // bind parameters
      //     todo : validate that all query parameters were bound?
      
      //这里才是我们这篇文章的主要想去探索的,如何打印展示的sql参数.
      int paramBindingPosition = 1;
      paramBindingPosition += limitHandler.bindLimitParametersAtStartOfQuery( limit, preparedStatement, paramBindingPosition );
      for ( JdbcParameterBinder parameterBinder : jdbcSelect.getParameterBinders() ) {
        parameterBinder.bindParameterValue(
            preparedStatement,
            paramBindingPosition++,
            jdbcParameterBindings,
            executionContext
        );
      }

      .....这部分代码省略
  }

由上面代码不难看出,两个点:

我们想打印的SQL:finalSql

我们想打印的SQL 预执行中的绑定的参数: jdbcSelect.getParameterBinders()

  • 从parameterBinder.bindParameterValue调用点入口进入。

    整个调用链路:

    IMG

着重看一下org.hibernate.type.descriptor.jdbc.BasicBinder#bind方法:

@Override
  public final void bind(PreparedStatement st, J value, int index, WrapperOptions options) throws SQLException {
    if ( value == null ) {
    //从代码中看出,日志的级别是trace级别。开启的JbdcBindingLogging的trace级别的日志就可以打印参数.
      if ( JdbcBindingLogging.TRACE_ENABLED ) {
        JdbcBindingLogging.logNullBinding(
            index,
            jdbcType.getDefaultSqlTypeCode()
        );
      }
      doBindNull( st, index, options );
    }
    else {
      if ( JdbcBindingLogging.TRACE_ENABLED ) {
        JdbcBindingLogging.logBinding(
            index,
            jdbcType.getDefaultSqlTypeCode(),
            getJavaType().extractLoggableRepresentation( value )
        );
      }
      doBind( st, value, index, options );
    }
  }

从代码中看出,日志的级别是trace级别。开启的JbdcBindingLogging的trace级别的日志就可以打印参数.

如何开启JbdcBindingLogging的trace级别日志。

public @interface SubSystemLogging {
  /**
   * Base category name for sub-system style logging
   */
  String BASE = "org.hibernate.orm";

  .....
}

public interface JdbcBindingLogging {
  String NAME = SubSystemLogging.BASE + ".jdbc.bind";

  Logger LOGGER = Logger.getLogger( NAME );

  boolean TRACE_ENABLED = LOGGER.isTraceEnabled();
}

由上面的两段代码的定义,可以看出,JdbcBindingLogging的类中定义的Logger的Name为"org.hibernate.orm.jdbc.bind",有Logger基础的应该知道再知道如何配置日志,这下知道怎么打印SQL参数了吧。

springboot的application.yml文件中设置:

logging:
  level:
    org:
      hibernate:
        orm:
          jdbc:
            bind: trace

即可打印日志:

Hibernate: select u1_0.id,u1_0.create_time,u1_0.nickname,u1_0.password,u1_0.update_time,u1_0.username from user u1_0 where u1_0.nickname=? limit ?,?
2023-02-14T13:44:01.545+08:00 TRACE 97770 --- [nio-1234-exec-8] org.hibernate.orm.jdbc.bind              : binding parameter [1] as [VARCHAR] - [五玄]
2023-02-14T13:44:01.549+08:00 TRACE 97770 --- [nio-1234-exec-8] org.hibernate.orm.jdbc.bind              : binding parameter [2] as [INTEGER] - [10]
2023-02-14T13:44:01.550+08:00 TRACE 97770 --- [nio-1234-exec-8] org.hibernate.orm.jdbc.bind              : binding parameter [3] as [INTEGER] - [10]

总结

为了打印日志,网上找了许久,各类大咖没说一个所以然来,自己翻出来看看,总结一下供后续有需要的人借鉴。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
10天前
|
SQL Java 数据库连接
mybatis使用四:dao接口参数与mapper 接口中SQL的对应和对应方式的总结,MyBatis的parameterType传入参数类型
这篇文章是关于MyBatis中DAO接口参数与Mapper接口中SQL的对应关系,以及如何使用parameterType传入参数类型的详细总结。
22 10
|
1月前
|
存储 SQL 关系型数据库
【MySQL调优】如何进行MySQL调优?从参数、数据建模、索引、SQL语句等方向,三万字详细解读MySQL的性能优化方案(2024版)
MySQL调优主要分为三个步骤:监控报警、排查慢SQL、MySQL调优。 排查慢SQL:开启慢查询日志 、找出最慢的几条SQL、分析查询计划 。 MySQL调优: 基础优化:缓存优化、硬件优化、参数优化、定期清理垃圾、使用合适的存储引擎、读写分离、分库分表; 表设计优化:数据类型优化、冷热数据分表等。 索引优化:考虑索引失效的11个场景、遵循索引设计原则、连接查询优化、排序优化、深分页查询优化、覆盖索引、索引下推、用普通索引等。 SQL优化。
397 15
【MySQL调优】如何进行MySQL调优?从参数、数据建模、索引、SQL语句等方向,三万字详细解读MySQL的性能优化方案(2024版)
|
5月前
|
SQL Java 数据库连接
JDBC的连接参数的设置导致rowid自动添加到sql
JDBC的连接参数的设置导致rowid自动添加到sql
48 1
|
3月前
|
SQL 数据库 Python
【Python】已完美解决:(executemany()方法字符串参数问题)more placeholders in sql than params available
【Python】已完美解决:(executemany()方法字符串参数问题)more placeholders in sql than params available
53 1
|
4月前
|
SQL DataWorks 关系型数据库
DataWorks产品使用合集之如何将硬编码的配置值(例如SQL查询中的固定值)更改为调度参数
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
72 7
|
3月前
|
SQL
自定义SQL,可以利用MyBatisPlus的Wrapper来构建复杂的Where条件,如何自定义SQL呢?利用MyBatisPlus的Wrapper来构建Wh,在mapper方法参数中用Param注
自定义SQL,可以利用MyBatisPlus的Wrapper来构建复杂的Where条件,如何自定义SQL呢?利用MyBatisPlus的Wrapper来构建Wh,在mapper方法参数中用Param注
|
3月前
|
SQL Cloud Native 关系型数据库
云原生数据仓库使用问题之控制JDBC方式请求的SQL大小限制的参数是什么
阿里云AnalyticDB提供了全面的数据导入、查询分析、数据管理、运维监控等功能,并通过扩展功能支持与AI平台集成、跨地域复制与联邦查询等高级应用场景,为企业构建实时、高效、可扩展的数据仓库解决方案。以下是对AnalyticDB产品使用合集的概述,包括数据导入、查询分析、数据管理、运维监控、扩展功能等方面。
|
4月前
|
SQL 分布式计算 前端开发
MaxCompute操作报错合集之SQL脚本设置参数set odps.mapred.reduce.tasks=18;没有生效,是为什么
MaxCompute是阿里云提供的大规模离线数据处理服务,用于大数据分析、挖掘和报表生成等场景。在使用MaxCompute进行数据处理时,可能会遇到各种操作报错。以下是一些常见的MaxCompute操作报错及其可能的原因与解决措施的合集。
137 5
|
4月前
|
分布式计算 DataWorks 大数据
MaxCompute产品使用合集之odps.sql.mapper.split.size和odps.stage.mapper.split.size这两个参数的区别是什么
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
|
4月前
|
SQL 缓存 关系型数据库
PolarDB产品使用问题之已经修改了expire_logs_days参数并确认已生效,但在SQL查询中仍然显示为0,该怎么办
PolarDB产品使用合集涵盖了从创建与管理、数据管理、性能优化与诊断、安全与合规到生态与集成、运维与支持等全方位的功能和服务,旨在帮助企业轻松构建高可用、高性能且易于管理的数据库环境,满足不同业务场景的需求。用户可以通过阿里云控制台、API、SDK等方式便捷地使用这些功能,实现数据库的高效运维与持续优化。