【深入浅出JVM原理及调优】「搭建理论知识框架」全方位带你深度剖析Java线程转储分析的开发指南

news2025/2/28 19:53:21

这里写目录标题

  • 专栏介绍
  • 前提准备
  • 面向人群
  • 知识脉络
  • 分析线程转储
    • 线程转储分析的介绍
    • JVM和线程运行机制
      • JVM和中间件之间的软件交互
    • JVM线程转储
      • Java快照的基本信息
        • 内存回收日志
        • 线程转储分解概述
        • 全线程转储标识符
        • Java EE中间件,第三方和自定义应用程序线程
          • HotSpot VM Thread
        • HotSpot GC Thread
        • JNI全局引用计数
        • Java堆利用率视图
        • Java堆栈跟踪重新访问
          • Java堆栈跟踪必须始终从自下而上读取
      • 线程转储:线程堆栈跟踪分析

专栏介绍

学习JVM需要一定的编程经验和计算机基础知识,适用于从事Java开发、系统架构设计、性能优化、研究学习等领域的专业人士和技术爱好者。

前提准备

  • 编程基础:具备良好的编程基础,理解面向对象编程(OOP)的基本概念,熟悉Java编程语言。
  • 数据结构与算法:对基本的数据结构和算法有一定了解,理解内存管理、线程操作等基本概念。

面向人群

学习本专栏以及本章内容的前提和适用人群如下:

  • Java开发人员:JVM是Java程序的核心执行引擎,因此Java开发人员需要深入了解JVM的工作原理和运行机制,以优化程序性能并解决相关问题。
  • 系统架构师和高级工程师:对系统整体性能、稳定性有较高要求的人群,有必要深入理解JVM以优化系统性能。
  • Java程序员和技术爱好者:具备一定Java编程经验,有意向深入了解JVM内部工作原理的人群。
  • 研究人员和学生:从事计算机科学相关研究或学习的人群,有兴趣深入研究JVM内部原理和优化方法。
  • JVM运维工程师:负责JVM性能优化、故障排查和调优的专业人员,需要对JVM有深入的理解。

知识脉络

每位Java开发者都了解到Java字节码是在Java运行时环境(JRE)上执行的。JRE包含了最为关键的组成部分:Java虚拟机(JVM),它负责分析和执行Java字节码。通常情况下,大多数Java开发者无需深入了解虚拟机的内部运行原理。即使对虚拟机的运行机制不甚了解,也不会对开发工作产生太多影响。然而,对JVM有一定了解的话,将更有助于深入理解Java语言,并解决一些看似困难的问题。

本专栏全面系统地剖析了特定虚拟机产品(即HotSpot,Oracle官方虚拟机)的实现,本人不仅深刻地讲解了看似深奥的原理,还提供了大量易于上手的实践案例,下面是总体的JVM相关的知识拓扑架构。

tips:当然还有一些最新的JVM特性未在这张图并非展示本专栏的全部内容,另外还包含了最新的JVM特性。


分析线程转储

本文将教您如何分析JVM线程转储,并确定问题的根本原因。从我的角度来看,线程转储分析是任何参与Java EE生产支持的个人都需要掌握的最重要技能集。您可以从线程转储快照中获得的信息量通常远远超出了您的想象。

线程转储分析的介绍

在深入研究线程转储分析和问题模式之前,了解基本原理是至关重要的。

JVM和线程运行机制

“Java虚拟机是Java EE平台的基石,它为您的中间件和应用提供了运行环境。在这里,您的程序会被部署并得以运行。”

JVM是一种中间件软件,为Java/Java EE程序提供运行环境。它支持字节码格式的运行时,并具备多种特性,如IO设施、数据结构、线程管理、安全和监控。此外,JVM还通过垃圾收集器实现动态内存分配和管理。

JVM和中间件之间的软件交互

下面的图表显示了JVM、中间件和应用程序之间的高级交互视图。

这是一个展示JVM、中间件和应用程序之间典型而简单交互的图示。在标准的Java EE应用程序中,线程的分配主要在中间件内核和JVM之间完成(尽管在应用程序本身或某些API直接创建线程时可能会有一些例外,但这并不常见,需要非常小心地处理)。

注意,JVM本身会管理一些线程,例如垃圾收集(GC)线程,用于处理并发的垃圾收集任务。

由于大多数线程分配是由Java EE容器完成的,因此理解和识别线程堆栈跟踪,并正确地从线程转储数据中识别它们非常重要。这将帮助您快速了解Java EE容器试图执行的请求类型。

从线程转储分析的角度来看,您可以学习如何区分不同的线程池,并识别请求类型。这将帮助您更好地理解JVM中的线程池,并进行有效的分析。

JVM线程转储

JVM线程转储器是在特定时间生成的一个快照,它提供了所有已创建的Java线程的完整列表。这个转储器可以帮助您获取关于线程的详细信息,以便进行分析和调试。

Java快照的基本信息

找到的每个单独的Java线程都为您提供以下信息:

  • 线程名称:通常被中间件供应商用于识别线程Id及其关联的线程池名称和状态(正在运行、被卡住等)。
  • 线程类型和优先级等:守护进程prio=3 中间件软件通常创建它们的线程作为守护进程,这意味着它们的线程在后台运行;为其用户提供服务,例如您的Java EE应用程序
  • Java线程ID ex: tid=0x000000011e52a800 这是通过java.lang获得的Java线程ID。Thread.getId(),通常实现为一个自动增量的长1…n
  • 本地线程ID ex: nid=0x251c关键信息,因为这个本地线程ID允许您相关,例如哪些线程从操作系统的角度使用最多的CPU在您的JVM等。
  • Java线程状态和细节等:等待监视器输入[0x fffffff ea5afb000]java.lang.thread。状态:已阻塞(在对象监视器上)允许快速了解线程状态及其潜在的当前阻塞条件
  • Java线程堆栈跟踪:这是迄今为止您将从线程转储文件中找到的最重要的数据。这也是您将花费大部分分析时间的地方,因为Java堆栈跟踪为您提供了90%的信息,以便查明许多问题模式类型的根本原因。
  • Java堆分解:从HotSpot VM 1.6开始,您还将在线程转储快照的底部发现HotSpot内存空间利用率的细分,如Java堆(YoungGen,OldGen)和PermGen/metaspace。当怀疑过多的GC是可能的根本原因时,这一点非常有用,因此您可以对已找到的线程数据/模式进行开箱即用的相关性。
内存回收日志
Heap
PSYoungGen total 466944K, used 178734K [0xffffffff45c00000, 0xffffffff70800000,0xffffffff70800000)
eden space 233472K, 76% used 
[0xffffffff45c00000,0xffffffff50ab7c50,0xffffffff54000000)
from space 233472K, 0% used 
[0xffffffff62400000,0xffffffff62400000,0xffffffff70800000)
to space 233472K, 0% used 
[0xffffffff54000000,0xffffffff54000000,0xffffffff62400000)
PSOldGen total 1400832K, used 1400831K [0xfffffffef0400000, 
0xffffffff45c00000, 0xffffffff45c00000)
object space 1400832K, 99% used 
[0xfffffffef0400000,0xffffffff45bfffb8,0xffffffff45c00000)
PSPermGen total 262144K, used 248475K [0xfffffffed0400000, 
0xfffffffee0400000, 0xfffffffef0400000)
object space 262144K, 94% used 
[0xfffffffed0400000,0xfffffffedf6a6f08,0xfffffffee0400000)
线程转储分解概述

为了让你更好地理解,找到下面的图表,显示一个HotSpot VM线程转储及其常见的线程池的可视化分解发现:

您可以从HotSpot VM线程转储文件中找到一些信息。根据您的问题模式,其中的一些将比其他的更重要,现在,根据我们的示例Hotspot线程转储,在下面找到每个线程转储部分的详细说明。

全线程转储标识符

这基本上是唯一的关键字,一旦你生成线程转储(例如:通过UNIX,你可以在<PID>中找到。这是线程转储快照数据的开头。

Full thread dump Java HotSpot(TM) 64-Bit Server VM (20.0-b11 mixed mode):
Java EE中间件,第三方和自定义应用程序线程

这部分是线程转储的核心,您通常将在这里花费大部分的分析时间。找到的线程的数量将取决于您使用的中间件软件、第三方库(可能有自己的线程)和您的应用程序(如果创建任何自定义线程,这通常不是最佳实践)。

在我们的示例线程转储中,Weblogic是所使用的中间件。从Weblogic9.2开始,使用一个自调优线程池和唯一标识符“Weblogic.内核”。默认值(自调)。

"[STANDBY] ExecuteThread: '414' for queue: 'weblogic.kernel.Default (selftuning)'" daemon prio=3 tid=0x000000010916a800 nid=0x2613 in Object.wait() 
[0xfffffffe9edff000]
 java.lang.Thread.State: WAITING (on object monitor)
 at java.lang.Object.wait(Native Method)
 - waiting on <0xffffffff27d44de0> (a weblogic.work.ExecuteThread)
 at java.lang.Object.wait(Object.java:485)
 at weblogic.work.ExecuteThread.waitForRequest(ExecuteThread.java:160)
 - locked <0xffffffff27d44de0> (a weblogic.work.ExecuteThread)
 at weblogic.work.ExecuteThread.run(ExecuteThread.java:181)
HotSpot VM Thread

这是一个由Hotspot管理的内部线程,以便执行内部本机操作。通常,您不应该担心这个问题,除非您看到高CPU(通过线程转储和prstat /本地线程id相关性)。

"VM Periodic Task Thread" prio=3 tid=0x0000000101238800 nid=0x19 waiting on condition
HotSpot GC Thread

当使用HotSpot并行GC时(现在在使用多物理核硬件时很常见),HotSpot VM会默认创建或根据JVM调优特定#的GC线程。这些GC线程允许VM以并行的方式执行其定期的GC清理,从而导致GC时间的总体减少;以增加CPU利用率为代价。

"GC task thread#0 (ParallelGC)" prio=3 tid=0x0000000100120000 nid=0x3 runnable 
"GC task thread#1 (ParallelGC)" prio=3 tid=0x0000000100131000 nid=0x4 runnable

这也是至关重要的数据,因为当遇到与GC相关的问题时,如GC过多、内存泄漏过多等,您将能够使用本地id值(nid=0x3)将从OS / Java进程中观察到的任何高CPU与这些线程关联起来。

JNI全局引用计数

JNI(Java本机接口)全局引用基本上是从本地代码到由Java垃圾收集器管理的Java对象的对象引用。它的作用是防止收集本机代码仍在使用的对象,但在技术上讲,在Java代码中没有“实时”引用。

为了检测与JNI相关的泄漏,密切关注JNI的参考文献也很重要。如果程序直接使用JNI或使用第三方工具,如监控工具,容易导致本机内存泄漏,就会发生这种情况

JNI global references: 1925
Java堆利用率视图

这些数据被添加到JDK中,并为您提供了Hotspot堆的一个简短和快速的视图。我发现它很有用当故障排除GC相关问题以及高CPU因为你得到线程转储和Java堆在一个快照允许你确定(或排除)任何压力点在一个特定的Java堆内存空间以及当前线程计算目前正在完成。正如您在我们的示例线程转储中看到的,Java堆OldGen已经用爆了!

Heap
PSYoungGen total 466944K, used 178734K [0xffffffff45c00000, 
0xffffffff70800000, 0xffffffff70800000)
 eden space 233472K, 76% used 
[0xffffffff45c00000,0xffffffff50ab7c50,0xffffffff54000000)
 from space 233472K, 0% used 
[0xffffffff62400000,0xffffffff62400000,0xffffffff70800000)
 to space 233472K, 0% used 
[0xffffffff54000000,0xffffffff54000000,0xffffffff62400000)
PSOldGen total 1400832K, used 1400831K [0xfffffffef0400000, 
0xffffffff45c00000, 0xffffffff45c00000)
 object space 1400832K, 99% used
[0xfffffffef0400000,0xffffffff45bfffb8,0xffffffff45c00000)
PSPermGen total 262144K, used 248475K [0xfffffffed0400000, 
0xfffffffee0400000, 0xfffffffef0400000)
 object space 262144K, 94% used 
[0xfffffffed0400000,0xfffffffedf6a6f08,0xfffffffee0400000)

为了让您快速从线程转储中识别出问题模式,您首先需要了解如何读取线程堆栈跟踪以及如何正确地获取“故事”。这意味着,如果我让你告诉我线程#38在做什么;你应该能够精确地回答;包括线程堆栈跟踪是否显示了一个健康(正常)和挂起条件。

Java堆栈跟踪重新访问

你们大多数人都熟悉Java堆栈跟踪。这是我们在抛出Java异常时从服务器和应用程序日志文件中找到的典型数据。在此上下文中,Java堆栈跟踪为我们提供了触发Java异常的线程的代码执行路径,例如,一个java.lang.NoClassDefFound错误,java.lang.Nullpointer异常等。这样的代码执行路径使我们能够看到最终导致Java异常的不同代码层。

Java堆栈跟踪必须始终从自下而上读取
  • 底部的一行将公开请求的发起者,例如Java / Java EE容器线程。
  • 堆栈跟踪顶部的第一行将显示最后一个异常被触发的Java类。

让我们通过一个简单的例子来介绍一下这个过程。我们创建了一个示例Java程序,简单地执行一些类方法调用并抛出一个异常。所生成的程序输出如下所述:

JavaStrackTraceSimulator
Author: Pierre-Hugues Charbonneau
http://javaeesupportpatterns.blogspot.com
Exception in thread "main" java.lang.IllegalArgumentException: 
 at org.ph.javaee.training.td.Class2.call(Class2.java:12)
 at org.ph.javaee.training.td.Class1.call(Class1.java:14)
 at org.ph.javaee.training.td.JavaSTSimulator.main(JavaSTSimulator.java:20)
  • Java program JavaSTSimulator is invoked (via the “main” Thread)
  • The simulator then invokes method call() from Class1
  • Class1 method call() then invokes Class2 method call()
  • Class2 method call()throws a Java Exception: java.lang.IllegalArgumentException
  • The Java Exception is then displayed in the log / standard output

如您所示,导致此异常的代码执行路径总是从下向上显示。上面的分析过程对于任何Java程序员来说都应该是非常熟悉的。接下来您将看到的是,线程转储线程堆栈跟踪分析过程与上面的Java堆栈跟踪分析非常相似。

线程转储:线程堆栈跟踪分析

从JVM生成的线程转储为您提供了整个JVM进程中所有“已创建的”线程的代码级执行快照。已创建的线程并不意味着所有这些线程实际上都在做一些事情。在从Java EE容器JVM生成的典型线程转储快照中:

  • 一些线程可以执行原始的计算任务,如XML解析、IO /磁盘访问等。
  • 一些线程可能正在等待一些阻塞的IO调用,比如远程Web服务调用,DB/JDBC查询等。
  • 一些线程可能涉及到垃圾收集,例如GC线程。
  • 一些线程将等待一些工作要做(不做任何工作的线程通常处于等待状态)
  • 一些线程可能正在等待其他线程的完成工作,例如,线程等待获取某些对象上的监视器锁(同步块{})。

线程堆栈跟踪为您提供了其当前执行情况的快照。第一行通常包括线程的本机信息,如其名称、状态、地址等。必须从自下而上开始读取当前的执行堆栈跟踪。请遵循下面的分析过程。你使用线程转储分析的经验越多,你就能越快地阅读和识别每个线程所执行的工作:

  1. 开始从底部读取线程堆栈跟踪

  2. 首先,识别发起者(Java EE容器线程、自定义线程、GC线程、JVM内部线程、独立的Java程序“主”线程等)。

  3. 下一步是确定线程正在执行的请求的类型(WebApp、Web服务、JMS、Remote EJB(RMI)、内部Java EE容器等)。

  4. 下一步是从执行堆栈中跟踪您的应用程序模块涉及线程尝试执行的实际核心工作。分析的复杂性将取决于中间件环境和应用程序的抽象层。

  5. 下一步是查看在第一行之前的最后一个~10-20行。识别线程所涉及的协议或工作,例如HTTP调用、套接字通信、JDBC或原始计算任务,如磁盘访问、类加载等。

  6. 下一步是看第一行。第一行通常告诉线程状态上的LOT,因为它是在您拍摄快照时执行的当前代码片段。

  7. 最后两个步骤的结合将为您提供信息的核心,以总结线程所涉及的工作和/或挂起条件。

现在,使用从JBoss生产环境捕获的线程转储线程堆栈跟踪的真实示例,找到上述步骤的可视化细分。在本例中,许多线程在创建JAX-WS服务实例的新实例时都显示了类似的过度IO问题模式。

正如您所看到的,最后10行和第一行将告诉我们线程涉及什么挂起或慢状态,如果有的话。从底部开始的行将给我们提供发起者和请求类型的详细信息。
全方位带你深度剖析Java线程转储分析的开发指南

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1346818.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024任务驱动Java程序设计讲课提纲

文章目录 为何采用任务驱动&#xff1f;任务驱动Java程序设计课程概述项目一&#xff1a;踏上Java开发之旅任务1&#xff1a;安装配置JDK并开发第一个Java程序1、安装JDK2、配置JDK环境变量3、开发第一个Java程序 任务2&#xff1a;搭建Java集成开发环境IntelliJ IDEA1、安装In…

【微服务】springboot整合skywalking使用详解

目录 一、前言 二、SkyWalking介绍 2.1 SkyWalking是什么 2.2 SkyWalking核心功能 2.3 SkyWalking整体架构 2.4 SkyWalking主要工作流程 三、为什么选择SkyWalking 3.1 业务背景 3.2 常见监控工具对比 3.3 为什么选择SkyWalking 3.3.1 代码侵入性极低 3.3.2 功能丰…

计算器写作文

一起来交流编程吧【CSDN app】&#xff1a; http://qm.qq.com/cgi-bin/qm/qr?_wv1027&kx9pL9ccIHGKNLE0CWviAqQ_q6HzxomLW&authKeyVslKe623ptw8VRepda%2Bh0Ttr8Ruz8v%2FBW5HpVzyTWU7ECwpHIZpULMj6qIHYZBVb&noverify0&gro 计算器写作文 题目描述 众所周知&a…

大数据应用领域:数据驱动一切

大数据出现的时间只有十几年&#xff0c;被人们广泛接受并应用只有几年的时间&#xff0c;但就是这短短几年的时间&#xff0c;大数据呈现出爆炸式增长的态势。在各个领域&#xff0c;大数据的身影几乎无处不在。今天我们通过一些大数据典型的应用场景分析&#xff0c;一起来看…

初始Web服务器

一、web服务器 1、什么是web服务器&#xff1f; web服务器就是web项目的容器&#xff0c;我们将开发好的web项目部署到web容器中&#xff0c;才能使用网络中的用户通过浏览器进行访问。 一张图带你了解web服务器有啥作用&#xff1a; 在我的电脑上有一个已经做好的项目&#…

【实用工具】Tmux使用指南

Tmux 三个重要概念 session&#xff08;会话&#xff09;、window&#xff08;窗口&#xff09;、pane&#xff08;面板&#xff09; 一个会话可以有多个窗口&#xff0c;一个窗口可以划分为多个面板 注意在tmux中使用快捷命令的话&#xff0c;需要加上前缀ctrlb 关于session的…

01. BI - Project one, 员工离职预测

文章目录 项目概要数据集处理LRSVM Hi&#xff0c;你好。我是茶桁。 又是开始了一个新的阶段。我不建议一些没基础的同学直接从这里开始&#xff0c;还是要先去之前的课程里补补基础。有的时候即便依葫芦画瓢的把代码写出来了&#xff0c;但是基本原理不清楚。而有的时候&#…

【华为机试】2023年真题B卷(python)-关联子串

一、题目 题目描述&#xff1a; 给定两个字符串str1和str2&#xff0c; str1进行排列组合只要有一个为str2的子串则认为str1是str2的关联子串&#xff0c; 请返回子串在str2的起始位置&#xff0c;若不是关联子串则返回-1。 二、示例 示例1 输入输出示例仅供调试&#xff0c;后…

WSL使用VsCode运行cpp文件

文章目录 缘起主要步骤参考 缘起 今天在阅读《C20设计模式-可复用的面向对象设计方法&#xff08;原书第2版&#xff09;》的时候&#xff0c;遇到代码想要运行一下&#xff0c;于是决定使用wsl下的vscode配置cpp的环境。 主要步骤 1.安装gcc和g编译器 打开命令行输入wsl&am…

C++_模板

目录 1、函数模板 1.2 模板原理 2、多个模板参数 3、模板的显示实例化 4、模板的匹配 5、类模板 结语&#xff1a; 前言&#xff1a; 在C中&#xff0c;模板分为函数模板和类模板&#xff0c;而模板的作用就是避免了重复的工作&#xff0c;把原本是程序员要做的重复工作交…

JavaFX:MVC模式学习01-使用PropertyValueFactory将模型与视图绑定

PropertyValueFactory类是“TableColumn cell value factory”,绑定创建列表中的项。示例如下&#xff1a; TableColumn<Person,String> firstNameCol new TableColumn<Person,String>("First Name");firstNameCol.setCellValueFactory(new PropertyVal…

C语言实验4:指针

目录 一、实验要求 二、实验原理 1. 指针的基本概念 1.1 指针的定义 1.2 取地址运算符&#xff08;&&#xff09; 1.3 间接引用运算符&#xff08;*&#xff09; 2. 指针的基本操作 2.1 指针的赋值 2.2 空指针 3. 指针和数组 3.1 数组和指针的关系 3.2 指针和数…

CentOS 7 实战指南:目录操作命令详解

写在前面 想要在 CentOS 7 系统下更高效地进行目录操作吗&#xff1f;不要犹豫&#xff0c;在这里我为你准备了一篇精彩的技术文章&#xff01;这篇文章将带您深入了解 CentOS 7 下目录操作相关命令的使用方法。无论您是新手还是有一定经验的用户&#xff0c;这篇文章都将为您…

vue-springboot基于JavaWeb的家装一体化商城平台guptn

针对用户需求开发与设计&#xff0c;该技术尤其在各行业领域发挥了巨大的作用&#xff0c;有效地促进了家装一体化的发展。然而&#xff0c;由于用户量和需求量的增加&#xff0c;信息过载等问题暴露出来&#xff0c;为改善传统线下管理中的不足&#xff0c;本文将提出一套基于…

区块链的三难困境是什么,如何解决?

人们需要保持社交、工作和睡眠之间的平衡&#xff0c;并且努力和谐相处。同样的概念也反映在区块链的三难困境中。 区块链三难困境是一个术语&#xff0c;指的是现有区块链的局限性&#xff1a;可扩展性、安全性和去中心化。这是一个存在了几十年的设计问题&#xff0c;其问题的…

学习动态规划解决不同路径、最小路径和、打家劫舍、打家劫舍iii

学习动态规划|不同路径、最小路径和、打家劫舍、打家劫舍iii 62 不同路径 动态规划&#xff0c;dp[i][j]表示从左上角到(i,j)的路径数量dp[i][j] dp[i-1][j] dp[i][j-1] import java.util.Arrays;/*** 路径数量* 动态规划&#xff0c;dp[i][j]表示从左上角到(i,j)的路径数量…

【深度解析C++】const成员函数

系列文章目录 &#x1f308;座右铭&#x1f308;&#xff1a;人的一生这么长、你凭什么用短短的几年去衡量自己的一生&#xff01; &#x1f495;个人主页:清灵白羽 漾情天殇_计算机底层原理,深度解析C,自顶向下看Java-CSDN博客 ❤️相关文章❤️&#xff1a;Cthis指针&#xf…

野火霸道-V2+3.2寸屏+FreeRTOS+LVGL移植

摘要 基于野火霸道-V23.2寸屏的开发板&#xff0c;下载器为STLINK分为两个版本&#xff0c;FreeRTOS和裸机版本 裸机 裸机准备 lvgl v8.2版本的源码野火的《触摸画板-3.2寸》与《基本定时器》的代码例程 移植 将基本定时器代码移植到触摸画板-3.2寸的例程中&#xff0c;…

java springboot将接口查询数据放在系统中 一小时系统更新一次 避免用户访问接口查询数据库缓慢

真到了公司 很多数据库表 特别是常用的功能业务对应的 都是几百万条起步的数据 查询会比较缓慢 那么 我们就可以不用每次都真的查询数据库 例如 我这里有一个接口 通过 封装的 IBookService.list 函数去查询数据库 接口返回是这样的 我们先在启动类 条件装配上 这个接口所在的…

MySQL所有常见问题

一、事务 定义:一组操作要么全部成功,要么全部失败,目的是为了保证数据最终的一致性 在MySQL中,提供了一系列事务相关的命令: start transaction | begin | begin work:开启一个事务commit:提交一个事务rollback:回滚一个事务事务的ACID 原子性(Atomicity):当前事…