ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

IDEA中输出SQL的七种方法:日志配置、插件还原与脚本生成实战

IDEA中输出SQL的七种方法:日志配置、插件还原与脚本生成实战 平时排查接口问题十次里有八次都要看SQL。你在IDEA里写Java项目会写SQL只是基本功能在日志里把SQL准确捞出来、带上参数还原成一条能直接执行的语句这才是日常开发中最有价值的技能之一。这篇文章就把我在IDEA里弄出SQL语句的几种方法完整捋一遍从框架自带的日志配置到插件一键还原再到Database面板生成脚本和p6spy拦截器全部覆盖。无论你是刚入行的小白还是写了好几年业务代码的老手照着做基本能覆盖你的所有输出场景。先说明一下IDEA输出SQL语句这个说法其实包含两层意思。一层是在程序运行过程中把框架拼接出来的SQL打印到控制台或者日志文件方便你排错另一层是直接利用IDEA的数据库工具和插件把表结构、数据、甚至一段JSON快速变成SQL脚本。这两种需求对应的方法完全不同但很多人只知其一不知道还有更省事的方案。1. 为什么要在IDEA里折腾“输出SQL语句”这件事先把动机说透不然很多人看到标题会觉得自己用不上。实际开发里你写的代码是查用户列表但框架最终生成的可能是三张表关联join再带两个子查询的复杂SQL。排查慢查询、定位数据对不上、清理脏数据的时候你光看代码根本看不出问题必须拿到那条真实执行的SQL粘到数据库客户端里跑一遍才能复现问题。另一个高频场景是写测试数据。项目联调时数据库里没几条可用数据你又不方便每张表手动insert这时候如果在IDEA里对着一张表就能直接生成批量INSERT语句填好数据一把梭效率翻好几倍。还有一类场景是压测和性能优化。你拿到一条慢SQL想看看它的执行计划通常也是从日志里把SQL抄出来放到数据库工具的Explain里跑。这一步听起来简单实际操作时如果SQL很长、参数很多从日志里手动拼完整SQL非常容易出错而且浪费时间。所以这篇文章的核心目的就是帮你省掉那些机械、重复、容易错的手工步骤。下面的方法我都按配置成本从低到高来排你可以根据自己的项目类型直接选。2. JPA/Hibernate的show-sql零成本但别忽视的输出方式很多人用Spring Data JPA开发时第一反应是我的SQL呢因为框架默认不打印SQL。打开方式其实非常简单大多数项目只要在配置里加一行就好了。2.1 show-sql怎么开、日志格式怎么看如果你的项目是基于Spring Boot的在application.yml或application.properties里加spring: jpa: show-sql: true properties: hibernate: format_sql: true第一行是总开关控制台就会打印出Hibernate的SQL第二行是让SQL按格式化输出不然一行长SQL挤在一起阅读难度极大。打开之后你会看到类似这样的输出Hibernate: select u.id, u.name, u.email from users u where u.status? and u.dept_id?注意这里只有SQL模板问号代表参数Hibernate默认不会把参数值也打出来。如果你想看到具体绑定的参数值需要继续配日志级别logging: level: org.hibernate.SQL: DEBUG如果你用的是Spring Boot 3.xHibernate版本比较高建议把日志级别换成logging: level: org.hibernate.orm.jdbc.bind: TRACE这样控制台才会输出每个问号对应的实际参数值否则你会看到SQL却不知道参数是什么排错效率直接打五折。2.2 提高日志可读性的两个配置show-sql打开后默认输出用的是System.out这意味着它不会进入你的logback或log4j2文件只出现在IDEA的Run控制台里。如果你需要保存日志文件供事后分析尽量别只用show-sql而是配合日志框架一起看。我实际项目里常用的组合是关掉show-sql避免控制台刷屏只通过日志级别来控制SQL输出spring: jpa: show-sql: false properties: hibernate: format_sql: true logging: level: org.hibernate.SQL: DEBUG org.hibernate.type.descriptor.sql: TRACE这样既能保持控制台干净又能让日志进入统一的日志文件。再配合IDEA的日志控制台颜色区分SQL语句会自动显示成不同颜色肉眼定位速度会快很多。2.3 我的实操心得JPA的show-sql有个问题它打出来的SQL和数据库客户端里能执行的SQL有差距。因为它是Hibernate底层生成的不同的方言dialect生成的语句会有细微差别比如分页SQL在MySQL下的写法是带limit的而PostgreSQL下是带limit offset的贴出来跑的时候要注意数据库类型是否一致。另外JPA中如果你用了实体关系关联比如ManyToOne默认的FetchType是EAGER日志里会出现多条SQL连续输出的情况这叫N1查询。看到这个不用慌SQL能输出出来本身就是排查的第一步你正好可以通过这些SQL判断到底发起了多少次查询。3. MyBatis日志输出最常用但也最容易被忽略的参数MyBatis在整个Java生态里占有率极高它的SQL日志输出方法和JPA完全不同坑也更多。3.1 核心配置log-impl到底填什么MyBatis的SQL打印核心在一个配置项mybatis.configuration.log-impl。这个值写成什么直接决定你在控制台能不能看到SQL。在Spring Boot的application.yml中配置mybatis: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl配置成这个类MyBatis会把SQL信息通过System.out打印到控制台。这是最轻量、最无脑的方式适合本地开发快速看SQL。如果你希望SQL走日志框架而不是直接输出到控制台可以换成mybatis: configuration: log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl然后配置对应logger级别logging: level: com.example.mapper: DEBUG注意这里的com.example.mapper不要照抄要换成你自己Mapper接口所在的包名。这是很多新手最容易踩的坑。你把级别写到com.example甚至root上日志量会大得吓人而且不好过滤。只针对mapper包开DEBUG是控制日志噪音的关键。3.2 日志框架配合logback/log4j2里的精细控制如果你的项目用的是logbackSpring Boot默认只开Logback级别也是不够的因为MyBatis的日志是分命名空间输出的。每一个Mapper接口对应一个logger名称。比如logger namecom.example.mapper.UserMapper levelDEBUG/但实际开发中一张张表配置logger太累直接配置整个mapper包范围内的logger就够logger namecom.example.mapper levelDEBUG/这样配置后执行MyBatis的查询时日志会输出Preparing和Parameters两行 Preparing: select * from users where id ? and name ? Parameters: 1(String), 张三(String)比JPA的日志要直观得多参数值也带了类型。这里算是我个人最喜欢的输出形态一眼就能看出SQL模板和参数值。3.3 实测对比我给的配置模板最终给你一个可以直接抄的完整配置mybatis: configuration: log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl mapper-locations: classpath:mapper/*.xml logging: level: com.example.mapper: DEBUG com.example.service: WARN这里把service层保持WARN级别避免mybatis信息被淹没。如果你还用了PageHelper分页插件可能需要再把com.github.pagehelper的logger打开才能看到Count SQL和Page SQL分别执行的情况这对于排查分页总数不对的问题非常有用。4. MyBatis Log Plugin从日志到可执行SQL的一键还原前面的输出方式都有一个痛点SQL和参数是分开的Preparing一行、Parameters一行。你需要人工把问号替换成参数值才能拿到一条完整SQL。参数少还好说参数一多替换过程非常痛苦。这时候IDEA插件MyBatis Log Plugin就能派上大用场。4.1 插件的定位和安装MyBatis Log Plugin可以直接把框架打印出来的日志自动拼成一条可以执行的SQL并且单独显示在一个Log窗口里。它本质上是解析IDE控制台里的日志文本把Preparing和Parameters的内容合并再把参数填回占位符。安装方式很简单IDEA菜单栏打开Settings - Plugins - Marketplace搜索MyBatis Log直接安装即可。插件有社区版也有付费版免费版已经够日常使用付费版多了一些历史记录保留和自动复制的功能。我建议先从免费版开始用顺手了再决定要不要升级。4.2 使用步骤和效果展示安装完成后什么都不用改你的项目只要按上面配置开启了MyBatis日志输出在Run窗口执行接口以后MyBatis Log窗口会自动收集日志并渲染成可执行的SQL。插件界面上会有几个按钮最常用的是Format和Copy。点击Format可以美化SQL排版点击Copy就是直接复制完整的SQL语句。你完全可以做到接口请求进来的那一刻SQL就生成好放在剪贴板里直接粘到Navicat或者IDEA自带的Database工具里跑中间不需要任何手工替换。4.3 插件失效、日志错乱这些坑插件虽好但有一些前提条件要满足第一插件解析的是MyBatis的日志输出所以前提是你的项目已经开启了MyBatis日志而且日志格式是标准的Preparing Parameters。如果你用了log-impl: StdOutImpl控制台能看但插件可能识别不到建议用Slf4jImpl并配置logger级别。第二如果你的项目用了连接池的SQL日志比如Druid的StatFilter日志或者HikariCP自带的debug日志插件是解析不了的因为格式不对。你需要保持MyBatis自己的日志输出。第三IDEA升级到新版本后部分旧版插件可能会失效。如果发现Log窗口不出现SQL了先看插件是否支持你的IDEA版本再看是否要更新插件版本。这个是最常见的兼容性问题排查第一站就是插件的Release Notes。5. IDEA Database面板把表结构、数据直接变成SQL脚本很多人以为IDEA的Database工具只是用来连数据库跑SQL的其实它有一个非常强大的功能生成SQL脚本。这在建表、造数据、同步数据结构时非常省事。5.1 从表结构生成DDL在IDEA右侧打开Database面板连接上你的数据库找到某张表右键选择SQL Scripts - Generate DDL。这样IDEA会根据表结构生成完整的建表语句包括字段、类型、主键、索引、外键以及表注释。拿到的DDL可以直接在新环境建表也可以用于代码评审时展示表变更。这个功能对比Navicat的转储SQL好处是它只生成一张表的结构不会把权限、用户、视图等无关信息带出来干净利落适合开发过程中做增量变更。5.2 直接生成数据脚本INSERT语句表结构能生成数据也能生成。同样是右键表名选择Import Data from Files或者用Data Editor打开表数据后右键选择Generate SQL - Insert Statements。举个例子我需要给测试环境造一批用户数据我先在临时表里手动插入几条记录然后用这个功能一键生成INSERT脚本再发给同事在另一套环境执行。比手动写一堆insert要快得多还能避免字段写错。更实用的一点是这个功能支持选中多行数据生成INSERT生成结果带完整字段列表可读性很高。如果你需要定期把A环境的数据同步到B环境这个方法可以帮你省去安装额外同步工具的麻烦。5.3 像连数据库客户端一样用Console执行SQLIDEA的Database面板里也可以打开一个Console执行SQL语句这本身就是IDEA提供的数据库客户端功能。在这个Console里你可以直接编写和执行SQL查看执行计划和结果集。如果你不想为了看一条SQL就打开Navicat或其他客户端直接在IDEA里就能完成全部操作。对于从日志或插件里复制出来的SQL我一般的处理流程是切到IDEA的Database Console粘贴SQL选中部分或全部执行。执行完成后还可以右键点击结果集选择Export Data导出CSV或JSON文件直接就能作为接口返回数据的mock数据源。Console加Export Data这个组合是我实测下来处理SQL结果最顺的流程特别是需要把SQL结果转成JSON给前端联调时一步到位。6. p6spy拦截器应用运行时输出最完整的SQL前面说的几种方法有个共同前提SQL框架必须是JPA或MyBatis。但如果你用的是Spring JDBC Template甚至是一个内部封装过的不支持SQL输出的老框架那日志中就很难拿到SQL了。这时p6spy就派上用场了。6.1 p6spy是什么、和在框架层打印有何不同p6spy是一个数据库连接驱动代理它拦截JDBC层面的所有操作任何PreparedStatement执行时的SQL语句、参数值、执行耗时它都能抓取到并输出。也就是说它不关心你的上层用的是MyBatis还是Hibernate甚至不关心你是不是用了DAO框架只要最后是JDBC执行的它都能打印出来。相比show-sql和MyBatis日志p6spy最大的优势是直接输出带参数的完整SQL不需要再手工拼参数而且能看到每个语句的执行耗时和执行次数。这对定位哪条SQL跑了多久特别有用。6.2 集成与配置步骤引入依赖dependency groupIdp6spy/groupId artifactIdp6spy/artifactId version3.9.1/version /dependency然后在Spring Boot的配置里替换数据源驱动spring: datasource: driver-class-name: com.p6spy.engine.spy.P6SpyDriver url: jdbc:p6spy:mysql://localhost:3306/test这里有个重点url前缀必须改成jdbc:p6spy:后面再接真正的JDBC地址。再创建spy.properties配置文件放在classpath下内容是appendercom.p6spy.engine.spy.appender.Slf4JLogger logMessageFormatcom.p6spy.engine.spy.appender.CustomLineFormat customLogMessageFormat%(executionTime)ms | %(sql)然后重启项目执行任意数据库操作日志里就会看到类似这样的内容12ms | select id,name,email from users where id 123 and status 1好的一点是参数已经完全替换进去了而且时间显示在前面方便判断慢SQL。6.3 我的取舍建议p6spy的缺点是多一层代理有轻微的性能损耗。所以生产环境我不建议开启但在测试环境、联调环境、压测环境它是排查问题的利器。另外p6spy默认会把所有SQL都打印出来包括连接池的验证查询比如select 1如果你的项目配置了连接池的testOnBorrow日志会非常啰嗦。解决办法是在spy.properties里配置exclude项把select 1这一类不需要的SQL排除掉excludeselect 1,sqlite_sequence这样日志噪音会小很多真正要排错的时候眼睛不会花。7. IDEA内置的杂项技巧格式化、JSON转SQL、执行计划里的SQL上面六种方法已经覆盖了绝大多数输出SQL的场景。但还有一些IDEA内置的小功能虽然不是严格意义的日志输出但对SQL的生成、整理、分析有奇效我也一并分享一下。7.1 SQL格式化与多行重排从日志、插件里复制出来的SQL大概率是一行或者几行挤在一起的直接阅读和用于diff都不方便。IDEA自带了SQL方言识别功能你把SQL粘贴到IDEA中在File - Settings - Languages Frameworks - SQL Dialects里设置好数据库类型然后按Ctrl Alt L就能自动格式化SQL。这个功能最好用的点是IDEA能把复杂的嵌套子查询、join条件、case when语句自动缩进和对齐比你手动排版快几个数量级。而且格式化之后再用Database面板的执行计划分析阅读体验完全不同。7.2 从JSON快速生成INSERT语句造测试数据时如果手头已经有了一份JSON格式的数据手动写INSERT语句很烦。IDEA里的Generate POJOs之类的插件生态中有类似JSON转SQL的小工具可以实现将JSON字段快速映射成SQL的INSERT语句。虽然这不是IDEA原生功能但搜索SqlGenerator、JsonToSql这些插件就能找到。我个人常用的另一个替代方案是先用Database面板生成一条insert模板再用工具批量把值替换进去。本质上思路是一样的都是减少重复劳动。7.3 执行计划里的SQL当你拿到一条慢SQL想分析它为什么慢的时候直接打开Database Console输入EXPLAIN关键字把SQL附在后面运行结果会显示访问类型、扫描行数、索引使用情况。这是排查慢SQL最直接的手段。IDEA会把这部分结果以表格形式展示比mysql命令行看起来清爽不少。需要注意的是不同数据库的EXPLAIN语法不一样MySQL支持EXPLAIN SELECT而SQL Server需要的是SET SHOWPLAN_ALL ON或者直接在客户端里看显示估计的执行计划。用IDEA时先确认你的连接类型再选择合适的语法不然会报语法错误。8. 常见问题排查与避坑实战无论你选哪种方式实际操作里总会遇到一些问题。我把自己踩过的坑和排查过的反馈整理成下面这张速查表。现象可能原因解决办法控制台有运行日志但没有SQL框架没开启SQL输出或日志级别不够检查show-sql/log-impl配置确认logger级别设为DEBUG或TRACESQL输出了但参数全是问号框架或日志配置只打印Preparing不打印参数MyBatis要开Parameters日志Hibernate要开org.hibernate.type或bind的TRACE复制出来的SQL手动替换参数时报错参数类型不一致比如字符串类型不带引号使用MyBatis Log Plugin或p6spy自动拼接避免手工操作日志量太大刷屏找不到自己的SQLmapper包级别开太高只针对具体mapper包或类设置DEBUG日志框架级别保持INFOMyBatis Log窗口没有内容插件解析不到日志确认log-impl用的是Slf4jImpl且日志输出到控制台或检查IDEA版本兼容性p6spy导致启动失败driver和url配置不匹配检查driver-class-name为P6SpyDriver且url前缀为jdbc:p6spy:Hibernate 6.x输出SQL格式和之前不一样新版本日志输出结构变化使用logging.level.org.hibernate.orm.jdbc.bind: TRACE打印参数日志中SQL和参数顺序对应不上MyBatis插件或日志框架干扰关闭其他SQL日志插件只保留一种输出方式生成的DDL和数据库实际结构不一致主键、注释、字段类型映射不全建议直接对数据库反向同步改完结构再生成DDL8.1 控制台有日志但没有SQL这个是最常见的问题。很多项目接了全局日志AOP把入参出参都打出来了但其实MyBatis的SQL根本没开。如果用的是MyBatis请重点确认log-impl配置如果用的是JPA请确认show-sql或日志级别是否真的生效。注意Spring Boot配置文件的优先级application.properties和application.yml同时存在时后者可能会导致前者配置失效。8.2 参数值类型和MySQL类型不匹配这是我在联调时被坑过最多次的坑。比如插入时间字段日志里显示参数是字符串类型但数据库要求的是TIMESTAMP如果直接用日志里的字符串SQL去执行数据库很可能会报类型转换错误。所以和DBA协作时拿到带参数的SQL后最好确认参数类型或者干脆用p6spy那种已经带类型的输出减少沟通损耗。8.3 日志太长被控制台截断IDEA控制台默认输出长度有限很长的SQL语句会被截断。解决办法是在Help - Edit Custom Properties里加一行idea.cycle.buffer.sizedisabled重启IDEA后控制台就不会截断了。这招很适合处理那种拼接了很多where条件的长SQL不然你只能看到一半SQL无从排查。8.4 多行SQL拼接错乱MyBatis日志输出时如果SQL里含有换行控制台显示会多出很多空格和换行。这是MyBatis的日志输出格式决定的不是你的SQL写错了。遇到这种情况建议直接使用插件还原后的SQL或者把SQL粘到IDEA里格式化一遍再看具体内容。8.5 插件失效情况和IDEA版本兼容MyBatis Log Plugin对IDEA新版本支持有一定延迟。每次IDEA大版本升级后插件市场可能提示兼容性问题。如果实在等不到插件更新可以退一步用p6spy临时替代或者升级到最新的IDEA企业版在Log Output里直接用Analyze Stacktrace特长。我个人在实际项目中的做法是Spring Boot MyBatis项目直接用MyBatis Slf4jImpl配logback关键排错时打开MyBatis Log PluginSpring Boot JPA项目优先用日志框架的DEBUG级别输出SQL和参数联调环境排查慢SQL、特别是涉及多表关联和子查询时直接上p6spy一次拿到完整SQL和耗时数据。这套组合用了很久基本覆盖了日常开发中会遇到的所有场景。最后再分享一个实用小技巧如果你经常需要把SQL发给别人或者收集到自己的SQL笔记库里可以在IDEA的Database Console里设置默认连接名这样SQL执行时自带当前库名复制出去执行的时候就不会出现数据库没选对这种低级错误。这个细节看着不起眼但在多人协作时能省掉很多无谓的沟通成本。
返回列表