Linux 日志处理三剑客:grep、awk、sed

📚 命令概述

🔍 grep - 全局正则表达式打印工具

命令全称 : Global Regular Expression Print
核心作用 : 在文件中搜索匹配指定模式的文本行
主要用途:

  • 查找包含特定关键字的日志行
  • 过滤日志内容
  • 统计匹配行数
  • 实时监控日志中的错误信息

一句话总结: grep 是"查找器",用于快速定位你想要的内容


📊 awk - 文本分析工具

命令全称 : Aho, Weinberger, Kernighan(三位创始人名字首字母)
核心作用 : 按行处理文本,按列提取和分析数据
主要用途:

  • 提取日志中的特定字段(如时间、IP、状态码)
  • 统计和计算(如求和、平均值、计数)
  • 条件过滤和格式化输出
  • 复杂的文本数据分析

一句话总结: awk 是"分析器",擅长处理结构化数据和统计计算


✏️ sed - 流编辑器

命令全称 : Stream Editor
核心作用 : 对文本进行批量编辑和转换
主要用途:

  • 替换文本内容
  • 删除特定行
  • 插入和追加内容
  • 提取指定行
  • 批量修改文件

一句话总结: sed 是"编辑器",用于批量修改和处理文本

📖 详细用法介绍

一、grep - 文本搜索命令

🎯 grep 是什么?

grep 是 Linux 中最常用的文本搜索工具,它能在文件中查找包含指定模式的行,并将这些行输出。就像在书中用荧光笔标记关键字一样,grep 帮你快速找到日志中的重要信息。

💡 为什么需要 grep?

在生产环境中,日志文件通常有几十万甚至上百万行,手动查找几乎不可能。grep 可以在几秒内从海量日志中找到你需要的错误信息、异常堆栈或特定事件。


📋 grep 常见使用场景

场景一:查看完整异常堆栈

问题: Java 异常堆栈通常是多行的,只看一行看不到完整信息

解决方案:

perl 复制代码
# 显示匹配行及其后 50 行
grep -A 50 "java.lang.NullPointerException" a.log


# 结合 less 分页查看
grep -A 50 "java.lang.NullPointerException" a.log | less

要点说明:

  • -A N 参数:显示匹配行之后的 N 行(After)

  • 异常堆栈通常需要看后续 20-50 行才能找到根本原因

  • less 命令用于分页查看:

    • ↑↓ 键滚动
    • G 跳到末尾
    • q 退出

场景二:实时监控新日志

问题: 需要实时观察线上服务是否出现错误

解决方案:

bash 复制代码
# 实时监控并显示异常及后续 50 行
tail -f a.log | grep -A 50 "java.lang.NullPointerException"


# 忽略大小写实时监控
tail -f a.log | grep -i -A 50 "error"

要点说明:

  • tail -f:实时追踪文件新增内容
  • 结合 grep 过滤关键异常
  • Ctrl + C 停止监控
  • -i 参数忽略大小写

场景三:查找历史/压缩日志

问题: 需要在多个日志文件或压缩日志中查找问题

查找所有 .log 文件:

bash 复制代码
# -H 参数显示文件名
grep -H -A 50 "java.lang.NullPointerException" *.log

查找压缩日志 (.gz)​:

arduino 复制代码
# zgrep 直接处理 .gz 文件,无需解压
zgrep -H -A 50 "java.lang.NullPointerException" *.gz

要点说明:

  • -H 参数:显示匹配内容所在的文件名
  • zgrep:专门处理压缩文件,无需手动解压
  • *.log*.gz:通配符匹配所有相关文件

场景四:统计异常出现次数

问题: 判断异常是偶发还是频繁发生

解决方案:

perl 复制代码
# 统计单个文件
grep -c "java.lang.NullPointerException" a.log


# 统计所有日志文件
grep -c "java.lang.NullPointerException" *.log

输出示例:

c 复制代码
app.log:15
app.log.1:3
app.log.2:0

要点说明:

  • -c 参数:只显示匹配行的数量,不显示内容
  • 快速判断问题严重程度

📊 grep 参数速查表

| 参数 | 含义 | 作用 | 示例 |
|--------|----------------|------------------|--------------------------|-------------|
| -A N | After | 显示匹配行之后的 N 行 | grep -A 10 "error" log |
| -B N | Before | 显示匹配行之前的 N 行 | grep -B 5 "error" log |
| -C N | Context | 显示匹配行上下各 N 行 | grep -C 25 "error" log |
| -i | ignore case | 忽略大小写 | grep -i "ERROR" log |
| -v | invert | 反向匹配(不包含) | grep -v "DEBUG" log |
| -H | with filename | 显示匹配的文件名 | grep -H "error" *.log |
| -h | no filename | 不显示文件名 | grep -h "error" *.log |
| -c | count | 统计匹配行数 | grep -c "error" log |
| -n | line number | 显示行号 | grep -n "error" log |
| -r | recursive | 递归搜索目录 | grep -r "error" /logs/ |
| -E | extended regex | 使用扩展正则 | `grep -E "error | warn" log` |
| -w | word | 完整单词匹配 | grep -w "error" log |


💡 grep 实战技巧

  1. 看异常必须用 -A - 单行看不到完整堆栈信息
  2. 实时监控用 tail -f | grep - 第一时间发现问题
  3. 压缩日志用 zgrep - 省时省力,无需解压
  4. 批量查找加 -H - 知道是哪个文件出的问题
  5. 统计频率用 -c - 判断问题严重程度
  6. 组合使用 -A -B -C - 查看完整上下文

二、awk - 文本分析命令

🎯 awk 是什么?

awk 是一个强大的文本分析工具,它把每一行看作一条记录,把每一列看作一个字段。就像 Excel 处理表格数据一样,awk 可以提取、计算、统计日志中的结构化数据。

💡 为什么需要 awk?

日志通常是结构化的(如:时间 | IP | 状态码 | 响应时间),当你需要:

  • 只看某几列数据
  • 统计某个字段的总和或平均值
  • 根据条件过滤数据
  • 进行复杂的数据分析

这时 awk 就是最佳选择!


📋 awk 基本概念

awk 如何看待文本:

bash 复制代码
2025-12-19 10:30:15 192.168.1.100 GET /api/user 200 150ms
    $1         $2        $3        $4    $5     $6  $7
   字段1     字段2     字段3    字段4  字段5  字段6 字段7

awk 的工作流程:

  1. 读取一行
  2. 按分隔符(默认空格/tab)分割成字段
  3. 对字段进行处理
  4. 输出结果
  5. 继续下一行

📋 awk 常见使用场景

场景一:提取特定列

问题: 只想看日志中的时间和错误信息

解决方案:

dart 复制代码
# 提取第1列(时间)和第5列(错误信息)
awk '{print $1, $5}' app.log


# 提取包含ERROR的行的特定字段
awk '/ERROR/ {print $1, $2, $NF}' app.log


# 提取第一列和最后一列
awk '{print $1, $NF}' app.log

输出示例:

yaml 复制代码
2025-12-19 NullPointerException
2025-12-19 TimeoutException

要点说明:

  • $1, $2, $3...:表示第1、2、3列
  • $NF:表示最后一列(Number of Fields)
  • $0:表示整行内容

场景二:统计分析

问题: 统计各状态码出现次数、计算平均响应时间

统计状态码出现次数:

css 复制代码
# 假设状态码在第9列
awk '{count[$9]++} END {for(code in count) print code, count[code]}' access.log

输出示例:

复制代码
200 15234
404 89
500 23

计算响应时间统计:

makefile 复制代码
# 假设响应时间在第10列
awk '{sum+=$10; count++} END {print "总计:", sum, "平均:", sum/count}' access.log

输出示例:

makefile 复制代码
总计: 125000 平均: 250

统计 IP 访问次数 TOP 10:

bash 复制代码
# 第1列是IP
awk '{ip[$1]++} END {for(i in ip) print ip[i], i}' access.log | sort -rn | head -10

输出示例:

yaml 复制代码
1523 192.168.1.100
892 192.168.1.101
456 192.168.1.102

要点说明:

  • count[$9]++:使用关联数组统计
  • END {}:所有行处理完后执行
  • sum+=:累加计算

场景三:条件过滤

问题: 只看响应时间超过1秒的请求

解决方案:

dart 复制代码
# 显示响应时间大于1000ms的请求
awk '$10 > 1000 {print $0}' access.log


# 显示特定时间段的日志
awk '$1 >= "2025-12-19 10:00:00" && $1 <= "2025-12-19 11:00:00"' app.log


# 显示状态码为5xx的错误
awk '$9 ~ /^5/ {print $0}' access.log


# 显示状态码不是200的请求
awk '$9 != 200 {print $0}' access.log

要点说明:

  • $10 > 1000:数值比较
  • $1 >= "xxx" && $1 <= "yyy":字符串比较和逻辑运算
  • $9 ~ /^5/:正则匹配(以5开头)
  • !=:不等于

场景四:格式化输出

问题: 让输出更易读,添加表头和格式

解决方案:

swift 复制代码
# 格式化输出,添加表头
awk 'BEGIN {print "时间\t\t\t状态码\t响应时间"} 
     {printf "%s\t%s\t%s\n", $1, $9, $10}' access.log


# 计算并格式化输出百分比
awk '{total++; if($9=="200") success++} 
     END {printf "成功率: %.2f%%\n", (success/total)*100}' access.log


# 添加行号
awk '{print NR, $0}' app.log

输出示例:

yaml 复制代码
时间			状态码	响应时间
2025-12-19	200	150
2025-12-19	404	50
成功率: 98.50%

要点说明:

  • BEGIN {}:处理第一行之前执行
  • printf:格式化输出(类似C语言)
  • %.2f:保留两位小数
  • NR:当前行号

📊 awk 内置变量速查表

变量 含义 说明 示例
$0 整行内容 当前处理的整行 awk '{print $0}'
$1, $2, $n 第n个字段 按分隔符分割的字段 awk '{print $1, $3}'
$NF 最后一个字段 Number of Fields awk '{print $NF}'
NR 行号 Number of Records awk 'NR==10 {print $0}'
NF 字段数 当前行有多少列 awk '{print NF}'
FS 字段分隔符 Field Separator(默认空格) awk 'BEGIN{FS=","}'
OFS 输出字段分隔符 Output Field Separator awk 'BEGIN{OFS="\t"}'

📊 awk 常用参数和操作符

| 参数/操作符 | 作用 | 示例 |
|-------------------|---------|---------------------------|-----|----------------|---|------------|
| -F | 指定字段分隔符 | awk -F',' '{print $1}' |
| ~ | 正则匹配 | awk '$0 ~ /ERROR/' |
| !~ | 正则不匹配 | awk '$0 !~ /DEBUG/' |
| == | 等于 | awk '$1 == "200"' |
| != | 不等于 | awk '$1 != "200"' |
| > < >= <= | 大小比较 | awk '$10 > 1000' |
| && | 逻辑与 | awk '$1==200 && $2>100' |
| ` | | ` | 逻辑或 | `awk '1==200 | | 1==201'` |


💡 awk 实战技巧

  1. 指定分隔符 : 日志不是空格分隔时用 -F

    bash 复制代码
    awk -F',' '{print $1}'  # CSV文件
    awk -F':' '{print $1}'  # 冒号分隔
  2. 多条件过滤 : 使用 &&||

    dart 复制代码
    awk '$9==200 && $10>1000 {print $0}'
  3. 统计去重: 使用关联数组

    scss 复制代码
    awk '{arr[$1]++} END {print length(arr)}'  # 统计唯一IP数
  4. BEGIN 和 END:

    • BEGIN:处理数据前执行(设置变量、打印表头)
    • END:处理数据后执行(打印统计结果)
  5. 格式化输出 : 使用 printf 而不是 print

    swift 复制代码
    awk '{printf "%-20s %10d\n", $1, $2}'

三、sed - 流编辑命令

🎯 sed 是什么?

sed 是一个流编辑器(Stream Editor),它可以对文本进行批量编辑操作。就像 Word 的"查找替换"功能,但 sed 更强大,可以处理整个文件或多个文件,支持正则表达式,还能删除、插入、提取行。

💡 为什么需要 sed?

当你需要:

  • 批量替换日志中的敏感信息
  • 删除调试日志(DEBUG 行)
  • 提取特定行号或匹配的行
  • 在特定位置插入内容
  • 不打开文件就能修改内容

这时 sed 就是最佳工具!


📋 sed 基本概念

sed 的工作流程:

  1. 读取一行到模式空间(Pattern Space)
  2. 执行编辑命令
  3. 输出结果到标准输出
  4. 继续下一行

sed 命令格式:

arduino 复制代码
sed [选项] '命令' 文件
sed [选项] -e '命令1' -e '命令2' 文件

📋 sed 常见使用场景

场景一:内容替换(最常用)​

问题: 需要批量替换日志中的文本

基本替换:

c 复制代码
# 替换每行第一个ERROR为[错误]
sed 's/ERROR/[错误]/' app.log


# 全局替换(替换所有,不只是第一个)
sed 's/ERROR/[错误]/g' app.log


# 替换并保存到新文件
sed 's/ERROR/[错误]/g' app.log > app_new.log


# 直接修改原文件(谨慎使用!)
sed -i 's/ERROR/[错误]/g' app.log


# 修改前备份原文件
sed -i.bak 's/ERROR/[错误]/g' app.log

高级替换:

bash 复制代码
# 只替换包含特定模式的行
sed '/2025-12-19/s/ERROR/[错误]/g' app.log


# 替换特定行号(第10行)
sed '10s/ERROR/[错误]/g' app.log


# 替换行号范围(10-20行)
sed '10,20s/ERROR/[错误]/g' app.log


# 忽略大小写替换
sed 's/error/[错误]/gi' app.log

要点说明:

  • s/old/new/:替换命令格式
  • g:全局替换(global)
  • i:忽略大小写(ignore case)
  • -i:直接修改文件(in-place)

场景二:删除行

问题: 删除日志中不需要的内容

解决方案:

bash 复制代码
# 删除空行
sed '/^$/d' app.log


# 删除包含DEBUG的行
sed '/DEBUG/d' app.log


# 删除第1-10行
sed '1,10d' app.log


# 删除最后一行
sed '$d' app.log


# 删除第5行
sed '5d' app.log


# 删除第3行到最后一行
sed '3,$d' app.log


# 删除不包含ERROR的行(保留ERROR行)
sed '/ERROR/!d' app.log

组合删除:

bash 复制代码
# 删除空行和DEBUG行
sed -e '/^$/d' -e '/DEBUG/d' app.log


# 或使用分号
sed '/^$/d; /DEBUG/d' app.log

要点说明:

  • d:删除命令(delete)
  • ^$:正则表达式,表示空行
  • !d:反向操作,删除不匹配的行

场景三:提取特定行

问题: 只想看日志中的某些行

解决方案:

bash 复制代码
# 只显示包含ERROR的行(类似grep)
sed -n '/ERROR/p' app.log


# 显示第10-20行
sed -n '10,20p' app.log


# 显示第一行
sed -n '1p' app.log


# 显示最后一行
sed -n '$p' app.log


# 显示第1行和最后一行
sed -n '1p;$p' app.log


# 显示匹配行及其后5行
sed -n '/ERROR/,+5p' app.log


# 显示从匹配行到文件末尾
sed -n '/ERROR/,$p' app.log


# 显示两个模式之间的内容
sed -n '/开始标记/,/结束标记/p' app.log

要点说明:

  • -n:静默模式,不自动打印
  • p:打印命令(print)
  • ,+5:当前行及后5行
  • 模式1,模式2:从模式1到模式2之间的行

场景四:插入和追加

问题: 在特定位置添加内容

解决方案:

bash 复制代码
# 在匹配行前插入内容
sed '/ERROR/i ====== 发现错误 ======' app.log


# 在匹配行后追加内容
sed '/ERROR/a ====== 错误结束 ======' app.log


# 在文件开头插入
sed '1i 日志开始时间: 2025-12-19' app.log


# 在文件末尾追加
sed '$a 日志结束' app.log


# 在第10行前插入
sed '10i 这是插入的内容' app.log


# 插入多行(使用\n)
sed '/ERROR/i ======\n错误详情\n======' app.log

要点说明:

  • i:在匹配行前插入(insert)
  • a:在匹配行后追加(append)
  • $:最后一行

场景五:多个操作组合

问题: 需要同时进行多种编辑操作

解决方案:

ini 复制代码
# 方法1:使用多个 -e
sed -e '/^$/d' -e 's/ERROR/[错误]/g' -e '/DEBUG/d' app.log


# 方法2:使用分号分隔
sed '/^$/d; s/ERROR/[错误]/g; /DEBUG/d' app.log


# 方法3:使用多行(可读性更好)
sed '
/^$/d
s/ERROR/[错误]/g
/DEBUG/d
' app.log


# 复杂处理示例
sed -n '
/ERROR/!d          # 只保留ERROR行
s/ERROR/[错误]/g   # 替换ERROR
s/WARN/[警告]/g    # 替换WARN
p                  # 打印结果
' app.log

📊 sed 命令速查表

命令 作用 示例
s/old/new/ 替换(substitute) sed 's/ERROR/错误/'
d 删除(delete) sed '/DEBUG/d'
p 打印(print) sed -n '/ERROR/p'
i 插入(insert) sed '/ERROR/i 标记'
a 追加(append) sed '/ERROR/a 标记'
c 替换整行(change) sed '/ERROR/c 错误行'
y 字符转换 sed 'y/abc/ABC/'
q 退出(quit) sed '10q'

📊 sed 参数速查表

参数 作用 示例
-n 静默模式,不自动打印 sed -n '/ERROR/p'
-e 执行多个编辑命令 sed -e 's/a/b/' -e 's/c/d/'
-i 直接修改文件 sed -i 's/old/new/g' file
-i.bak 修改前备份 sed -i.bak 's/old/new/g' file
-r 使用扩展正则 sed -r 's/[0-9]+/NUM/g'
-f 从文件读取命令 sed -f script.sed file

📊 sed 地址范围

地址 含义 示例
n 第n行 sed '5d' 删除第5行
n,m 第n到m行 sed '10,20d' 删除10-20行
n,+m 第n行及后m行 sed '10,+5d' 删除10行及后5行
n~m 从n开始每m行 sed '1~2d' 删除奇数行
$ 最后一行 sed '$d' 删除最后一行
/pattern/ 匹配的行 sed '/ERROR/d' 删除ERROR行
/p1/,/p2/ 从p1到p2 sed '/开始/,/结束/d'

💡 sed 实战技巧

  1. 先测试再修改 : 去掉 -i 先看效果

    bash 复制代码
    sed 's/ERROR/错误/g' app.log  # 先预览
    sed -i 's/ERROR/错误/g' app.log  # 确认后再修改
  2. 备份原文件 : 使用 -i.bak

    c 复制代码
    sed -i.bak 's/ERROR/错误/g' app.log  # 生成app.log.bak备份
  3. 使用正则表达式: 更灵活的匹配

    css 复制代码
    sed 's/[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}/IP_HIDDEN/g'
  4. 引用匹配内容 : 使用 &

    bash 复制代码
    sed 's/ERROR/【&】/g'  # ERROR变成【ERROR】
  5. 分组引用 : 使用 \1 \2

    ini 复制代码
    sed 's/$[0-9]*$-$[0-9]*$/\2-\1/g'  # 交换两个数字

四、grep + awk + sed 组合使用

🎯 三剑客协作

在实际工作中,这三个命令经常组合使用,各司其职:

  • grep:过滤出需要的行
  • awk:提取和统计数据
  • sed:格式化和替换内容

📋 实战组合案例

案例1:分析错误日志

bash 复制代码
# 1. 提取ERROR日志,统计各类错误次数
grep "ERROR" app.log | awk '{print $5}' | sort | uniq -c | sort -rn


# 输出示例:
#   152 NullPointerException
#    89 TimeoutException
#    23 IOException

流程说明:

  1. grep "ERROR":过滤出ERROR行
  2. awk '{print $5}':提取第5列(异常类型)
  3. sort:排序
  4. uniq -c:统计重复次数
  5. sort -rn:按数量倒序

案例2:分析慢请求

perl 复制代码
# 查找响应时间>1秒的请求,格式化输出
grep "access" app.log | awk '$10 > 1000 {print $1, $7, $10}' | sed 's/ms/毫秒/g'


# 输出示例:
# 2025-12-19 /api/user 1250毫秒
# 2025-12-19 /api/order 1800毫秒

流程说明:

  1. grep "access":过滤访问日志
  2. awk '$10 > 1000':过滤响应时间>1000ms
  3. print $1, $7, $10:提取时间、URL、响应时间
  4. sed 's/ms/毫秒/g':替换单位

案例3:统计每小时错误数

bash 复制代码
# 统计每小时的ERROR数量
grep "ERROR" app.log | awk '{print substr($1,1,13)}' | sort | uniq -c


# 输出示例:
#   45 2025-12-19 10
#   89 2025-12-19 11
#   23 2025-12-19 12

流程说明:

  1. grep "ERROR":过滤ERROR行
  2. awk '{print substr($1,1,13)}':提取时间到小时(前13个字符)
  3. sort | uniq -c:统计每小时出现次数

案例4:清理和格式化异常堆栈

perl 复制代码
# 提取异常堆栈并清理格式
grep -A 20 "Exception" app.log | sed '/^$/d' | awk '{print NR, $0}'


# 输出示例:
# 1 java.lang.NullPointerException
# 2     at com.example.Service.method(Service.java:100)
# 3     at com.example.Controller.handle(Controller.java:50)

流程说明:

  1. grep -A 20 "Exception":提取异常及后20行
  2. sed '/^$/d':删除空行
  3. awk '{print NR, $0}':添加行号

案例5:分析API调用情况

bash 复制代码
# 统计API调用次数TOP10
grep "API" access.log | awk '{print $7}' | sed 's/?.*//g' | sort | uniq -c | sort -rn | head -10


# 输出示例:
#  1523 /api/user
#   892 /api/order
#   456 /api/product

流程说明:

  1. grep "API":过滤API请求
  2. awk '{print $7}':提取URL
  3. sed 's/?.*//g':去掉查询参数
  4. sort | uniq -c:统计次数
  5. sort -rn | head -10:取TOP10

案例6:生成错误报告

bash 复制代码
# 生成今日错误统计报告
{
  echo "===== 错误日志报告 ====="
  echo "日期: $(date +%Y-%m-%d)"
  echo ""
  echo "错误总数:"
  grep -c "ERROR" app.log
  echo ""
  echo "错误类型分布:"
  grep "ERROR" app.log | awk '{print $5}' | sort | uniq -c | sort -rn
  echo ""
  echo "错误时间分布:"
  grep "ERROR" app.log | awk '{print substr($1,1,13)}' | sort | uniq -c
} | tee error_report.txt

五、实战技巧总结

🎯 选择合适的工具

需求 推荐工具 原因
查找关键字 grep 最快最简单
提取特定列 awk 专门处理列数据
统计计算 awk 支持数学运算
替换文本 sed 批量替换效率高
删除行 sed 灵活的行操作
复杂分析 awk 功能最强大
组合操作 grep+awk+sed 各取所长

💡 性能优化建议

  1. 先过滤再处理: 用 grep 先缩小范围

    lua 复制代码
    grep "ERROR" huge.log | awk '{统计}'  # 好
    awk '/ERROR/ {统计}' huge.log  # 较慢
  2. 避免不必要的管道: 能一步完成不要分多步

    perl 复制代码
    awk '/ERROR/ {print $1}' log  # 好
    grep "ERROR" log | awk '{print $1}'  # 多余
  3. 使用合适的工具: 不要用 sed 做 awk 的事

    bash 复制代码
    awk '{print $1}' log  # 好
    sed 's/.* $[^ ]*$$/\1/' log  # 复杂且慢

🔍 调试技巧

  1. 逐步调试: 一步步添加管道

    perl 复制代码
    grep "ERROR" log  # 第1步:看看过滤结果
    grep "ERROR" log | awk '{print $5}'  # 第2步:看看提取结果
    grep "ERROR" log | awk '{print $5}' | sort | uniq -c  # 第3步:完整流程
  2. 使用 head 限制输出: 避免刷屏

    bash 复制代码
    grep "ERROR" huge.log | head -20  # 只看前20行
  3. 保存中间结果: 方便调试

    lua 复制代码
    grep "ERROR" log > error.tmp
    awk '{print $5}' error.tmp > types.tmp
相关推荐
_UMR_32 分钟前
springboot集成Jasypt实现配置文件启动时自动解密-ENC
java·spring boot·后端
程序员小假38 分钟前
我们来说说 Cookie、Session、Token、JWT
java·后端
短剑重铸之日1 小时前
《SpringBoot4.0初识》第一篇:前瞻与思想
java·开发语言·后端·spring·springboot4.0
it_czz1 小时前
LangSmith vs LangFlow vs LangGraph Studio 可视化配置方案对比
后端
蓝色王者1 小时前
springboot 2.6.13 整合flowable6.8.1
java·spring boot·后端
花哥码天下2 小时前
apifox登录后设置token到环境变量
java·后端
hashiqimiya3 小时前
springboot事务触发滚动与不滚蛋
java·spring boot·后端
TeamDev3 小时前
基于 Angular UI 的 C# 桌面应用
前端·后端·angular.js
PPPHUANG3 小时前
一次 CompletableFuture 误用,如何耗尽 IO 线程池并拖垮整个系统
java·后端·代码规范