Unity_Obfuscator Pro代码混淆工具_学习日志
Unity_Obfuscator Pro代码混淆工具_学习日志
切勿将密码或 API 密钥存储在您附带的应用程序内。
混淆后的热更新暂时没有想到怎么办
Obfuscator 文档
https://docs.guardingpearsoftware.com/manual/Obfuscator/Description.html商店链接Obfuscator Pro(大约$70)
https://assetstore.unity.com/packages/tools/utilities/obfuscator-pro-89589
商店链接Obfuscator Free(免费版本)
https://assetstore.unity.com/packages/tools/utilities/obfuscator-free-89420在github上开源的另外一个混淆工具
https://github.com/DrFlower/Unity-Obfuscator反编译工具
https://github.com/icsharpcode/ILSpy
生成
https://github.com/icsharpcode/ILSpy/releases插件版本v5.3.0
警告
如果有代码热更新,使用使用混淆的时候请进行详细的测试,避免找不到方法名
(启用/禁用)string类型混淆
启用之后的代码
if (num == 666935005){_gameObject = base.gameObject.transform.Find(<PrivateImplementationDetails>{E1D950B9-0A02-402B-8227-E55CD61234BF}.a.h()).gameObject;num = -138089121;}
禁用之后的代码
if (num == -844616100){_gameObject = base.gameObject.transform.Find("hello12311").gameObject;num = -81965731;}
源码:
void Start(){GameObject _gameObject = gameObject.transform.Find("hello12311").gameObject;Debug.Log(_gameObject==null);}
如果有地方依赖于string类型,可以考虑把string类型混淆关掉
json数据读取
序列化为json需要添加:[System.Serializable] [DoNotRename]
这两个特性,一个是序列化的特性,一个是禁止混淆的特性。
向https://jsonplaceholder.typicode.com/todos/1
发送请求会获取到json:{ "userId": 1, "id": 1, "title": "delectus aut autem", "completed": false }
,然后继续序列化的时候,序列化为 TodoItem
,进行字段匹配的时候,因为TodoItem 已经被混淆了 ,json中的字段和TodoItem 中的字段就不匹配了,就找不到了,就会报错!
添加了
没有添加
看起来一样,插件会自己添加特性,但是插件添加的,不能运行,运行就崩溃了。
private IEnumerator SendRequest(){UnityWebRequest webre = UnityWebRequest.Get("https://jsonplaceholder.typicode.com/todos/1");yield return webre.SendWebRequest();if (webre.result != UnityWebRequest.Result.Success){Debug.LogError(webre.error);}else{Debug.Log(webre.downloadHandler.text);var tmp_data = JsonUtility.FromJson<TodoItem>(webre.downloadHandler.text);Debug.Log(tmp_data.id);}}[System.Serializable]
[DoNotRename]
public class TodoItem
{public int userId;public int id;public string title;public bool completed;
}
协程方法名混淆
其中IeCreateLanch1
IeCreateLanch3
IeCreateLanch4
不会被混淆方法名, IeCreateLanch2
会被混淆方法名称
void Start(){StartCoroutine(nameof(IeCreateLanch1));StartCoroutine(IeCreateLanch2());StartCoroutine("IeCreateLanch3");StartCoroutine("IeCreateLanch4");}private IEnumerator IeCreateLanch1(){GameObject.CreatePrimitive(PrimitiveType.Cube);Debug.Log(" StartCoroutine(nameof(IeCreateLanch1));");yield return null;}private IEnumerator IeCreateLanch2(){GameObject.CreatePrimitive(PrimitiveType.Capsule);Debug.Log(" StartCoroutine(IeCreateLanch2());");yield return null;}private IEnumerator IeCreateLanch3(){GameObject.CreatePrimitive(PrimitiveType.Cylinder);Debug.Log(" StartCoroutine(\"IeCreateLanch3\");");yield return null;}[DoNotRename]private IEnumerator IeCreateLanch4(){GameObject.CreatePrimitive(PrimitiveType.Sphere);Debug.Log("StartCoroutine(\"IeCreateLanch4\");");yield return null;}
在动画组件上使用公开的方法
动画事件,在这里被调用的方法建议加上[DoNotRenameAttribute] 放置被混淆
快速上手
启动插件
发布即可
详细教程
混淆器是一种软件工具,旨在将游戏、应用程序或程序的源代码转换为人类更难理解的版本,同时仍保持其原始功能。它通过将变量、方法和类重命名为无意义或误导性的名称,并以掩盖其逻辑和流程的方式更改代码结构来实现这一点。
使用 Obfuscator 的主要目的是保护软件的知识产权。通过使代码更难阅读和分析,未经授权的个人对软件进行逆向工程、复制或修改变得更具挑战性。这一额外的安全层有助于防止软件盗版、知识产权盗窃和未经授权的篡改,从而保护开发人员的工作和投资。
混淆_Obfuscation:代码混淆的常规设置。这包括要对哪些程序集进行模糊处理的规范,以及对它们各自的类和成员进行模糊处理的详细说明。
安全性_Security:包含高级安全设置,如“字符串混淆”、“随机代码生成”等。
兼容性_Compatibility:由于 Unity 的独特运行方式,某些第三方资源需要特定配置以确保与混淆兼容。
选项_Optional:包含可选的集成设置。例如,‘Custom Obfuscation Pattern’、‘Logging’、‘Name Mapping’ 等。
省流
下面是https://docs.guardingpearsoftware.com/manual/Obfuscator/Description.html
的电子翻译版本。
如果插件不能正确序列化?修改:Obfuscation 里的Assembly-Settings 的依赖项
。
添加随机代码:安全性_Security 下找 Add Random Code - Settings 关闭即可。
不混淆字符串:安全性_Security 下找 String - Settings 关闭即可。
混淆_Obfuscation
Assembly-Settings
管理需要混淆的程序集:
- 混淆 Assembly-CSharp:混淆默认的 Unity 程序集
Assembly-CSharp.dll
。该程序集包含未通过 Assembly Definition File 添加到子程序集中的代码。 - 混淆 Assembly-CSharp-firstpass:混淆默认的 Unity 插件程序集
Assembly-CSharp-firstpass.dll
。该程序集包含未通过 Assembly Definition File 添加到子程序集中的代码,并且可以在 Plugins 目录中找到。 - 混淆位于‘Assets’目录中的 Assembly Definition File:混淆通过 Assembly Definition File 在
[Root]/Assets
目录及其子目录中定义的子程序集中的代码。 - 混淆位于‘Packages’目录中的 Assembly Definition File:混淆通过 Assembly Definition File 在
[Root]/Packages
目录及其子目录中定义的子程序集中的代码。 - 混淆外部程序集:如果只想混淆特定程序集或第三方程序集,请在此处添加。
- 依赖项:如果混淆器无法解析第三方依赖,则需在这里添加其完整路径。
NameSpace-Settings
管理命名空间及其类的混淆:
- 混淆命名空间:混淆类的命名空间。此选项必须启用才能混淆 MonoBehaviour 类。
- 跳过以下命名空间:在此处添加希望忽略混淆的命名空间。这将跳过这些命名空间内所有类及其成员的混淆。输入的命名空间被视为前缀,因此输入 GoogleSdk 也会跳过 GoogleSdk.Lib。
- 反转命名空间忽略:反转命名空间忽略。启用后,只有那些指定命名空间内的类和它们的成员会被混淆。
Class - Settings
管理类的混淆:
- 基于访问级别混淆(内部/私有/受保护/公共):根据访问级别混淆类名。
- 混淆抽象类:混淆抽象类的名字。
- 混淆泛型类:混淆泛型类的名字。
- 混淆可序列化类:混淆可序列化类的名字及字段。仅建议在数据在运行时序列化并在混淆之后使用时使用。否则,序列化类内的名称将不匹配并导致错误。
- 混淆 MonoBehaviour 子类:混淆 MonoBehaviour 类的名字。需要混淆命名空间。
- 混淆外部程序集中 MonoBehaviour 子类:混淆第三方或预编译程序集中的 MonoBehaviour 类的名字。需要混淆命名空间。
- 混淆 ScriptableObject 子类:混淆 ScriptableObject 类的名字及其字段。仅建议不在序列化 ScriptableObject 到 .assets 文件或通过 Unity 检查器赋值的情况下使用。否则保存的已混淆数据名称将不匹配并产生错误。
- 混淆 Playable 子类:混淆 Playable 类的名字。
Method - Settings
管理方法的混淆:
- 基于访问级别混淆(内部/私有/受保护/公共):根据访问级别混淆方法名。
Parameter - Settings
管理参数的混淆:
- 混淆方法参数:混淆通用方法参数。普通参数在构建代码中没有“名称”,只有 ID,所以不需要或不可能混淆。
- 混淆类参数:混淆通用类参数。
Field - Settings
管理字段的混淆:
- 基于访问级别混淆(内部/私有/受保护/公共):根据访问级别混淆字段名。
- 混淆序列化字段:混淆
MonoBehaviour/ScriptableObject
类中序列化字段的名称。这些字段带有SerializeField
属性。仅推荐在数据在运行时序列化并在混淆后使用,并且不通过 Unity 检查器分配的情况下使用。否则序列化类中的名称将不匹配并产生错误。 - 混淆 Unity 公开字段:混淆
MonoBehaviour/ScriptableObject
类中公开字段的名称。同样仅推荐在数据在运行时序列化并在混淆后使用,并且不通过 Unity 检查器分配的情况下使用。 - 混淆枚举值:混淆枚举中的字段名称。
Property - Settings
管理属性的混淆:
- 基于访问级别混淆(内部/私有/受保护/公共):根据访问级别混淆属性名。
Event - Settings
Event - Settings
管理事件的混淆:
- 基于访问级别混淆(内部/私有/受保护/公共):根据访问级别混淆事件名。
安全性_Security
Add Random Code - Settings 随机代码 - 设置
添加随机代码:
激活 以根据现有和新生成的方法注入随机代码。
Method Control Flow - Settings 方法控制流程 - 设置
方法中的控制流是指执行单个语句、指令或函数调用的顺序。控制流的混淆会导致分布式顺序,而不是默认的自上而下的顺序,因此很难理解该方法的实际作用。
String - Settings 字符串 - 设置
Supress ILDasm - Settings Supress ILDasm - 设置
将 SuppressILDasmAttribute 添加到程序集中。阻止 Visual Studio 等 IDE 调试代码。
Anti Tampering - Settings 防篡改 - 设置
在运行时执行微检查以防止程序集操作。一旦检测到篡改,应用程序将中止并出现 BadImageFormatException。
兼容性_Compatibility
建议自己看看,一般不需要处理,如果插件不能正常工作,则在Addressable 添加插件的地址,unity插件的地址
https://docs.guardingpearsoftware.com/manual/Obfuscator/Settings/Compatibility.html#common---settings
选项_Optional
日志记录 (Logging)
Obfuscator 包含一个内部的日志系统来记录其所有操作。默认情况下,日志将存储在 Assets/OPS/Obfuscator/Log/{BuildTarget}.txt
路径下。如果遇到任何问题,请将日志文件连同问题描述一起发送给Obfuscator团队以帮助诊断和解决问题。
设置选项
- 使用自定义日志文件 (Use a custom log file): 激活此设置以定义自定义日志文件位置。
- 自定义日志文件路径 (Custom log file path): 自定义日志文件的路径。
属性管理 (Attributes)
Obfuscator 提供了一系列属性来微调源代码级别的混淆过程。在此部分可以管理和自定义这些附加属性。
设置选项
- 自定义 ‘DoNotRename’ 属性 (Custom ‘DoNotRename’ Attributes):
DoNotRename
属性可以跳过类或成员的混淆。有时使用具有相同行为的自定义属性会更方便。在此处添加名称。
名称重命名 (Renaming)
您可以在此处自定义Obfuscator用于混淆源代码的字符集。还可以启用混淆映射文件的保存和加载功能。该文件记录了类、方法、字段等的原始名称及其对应的混淆名称。
设置选项
- 活动重命名模式 (Active renaming pattern): 使用预定义的字符集进行混淆或定义自己的字符集。根据构建目标,并非所有字符都受支持,但默认模式始终适用。
- 自定义重命名模式 (Custom renaming pattern): 如果选择使用自定义字符集,则在这里添加您想要使用的字符,无需任何分隔符。
- 加载混淆映射文件 (Load an obfuscation mapping file): 激活此设置以加载混淆映射文件。
- 加载映射文件路径 (Load mapping file path): 输入加载混淆映射文件的路径。
- 保存混淆映射文件 (Save an obfuscation mapping file): 激活此设置以保存混淆映射文件。
- 保存映射文件路径 (Save mapping file path): 输入保存混淆映射文件的路径。
映射文件的好处
- 一致的混淆: 确保相同的元素总是用相同的名称混淆,保持不同构建之间的一致性。
- 错误调试: 通过提供混淆元素的原始名称来帮助解析错误堆栈跟踪,使识别和解决问题更加容易。
特性
特性文档
https://docs.guardingpearsoftware.com/manual/Obfuscator/Attributes.html
-
DoNotRenameAttribute:
- 作用于类、字段、方法或其他成员,防止它们的名字被重命名(即不混淆名字)。
- 示例代码:
[DoNotRenameAttribute] public class MyClass {[DoNotRenameAttribute]public void MyMethod(); }
-
DoNotObfuscateClassAttribute:
- 应用于类上,防止整个类及其中的所有成员被混淆(除了方法体)。
- 示例代码:
[DoNotObfuscateClassAttribute] public class MyClass {public void MyMethod(); }
-
DoNotObfuscateMethodBodyAttribute:
- 应用于类或具体的方法上,防止方法体内的内容被混淆。
- 示例代码:
[DoNotObfuscateMethodBodyAttribute] public class MyClass {[DoNotObfuscateMethodBodyAttribute]public void MyMethod(){var someString = "This string will not be obfuscated";} }
-
DoNotUseClassForFakeCodeAttribute:
- 防止在类中添加假代码或随机代码,也禁止基于此类生成新的假类。
- 示例代码:
[DoNotUseClassForFakeCodeAttribute] public class MyClass {public void MyMethod(); }
-
ObfuscateAnywayAttribute:
- 强制混淆指定的类成员,即使其他设置阻止混淆。
- 示例代码:
[ObfuscateAnywayAttribute("CustomClassName")] public class MyClass {[ObfuscateAnywayAttribute("CustomMethodName")]public void MyMethod(); }
-
ObfuscationAttribute:
- 支持.NET框架内置的
System.Diagnostics.ObfuscationAttribute
,用于指定是否应将程序集、类型或成员排除在混淆之外。 - 示例代码:
[ObfuscationAttribute(Exclude = true, ApplyToMembers = false)] public class MyClass {[ObfuscationAttribute(Exclude = true, ApplyToMembers = false)]public void MyMethod(); }
- 支持.NET框架内置的
通过这些属性,开发者可以根据需要选择性地保护代码的部分不受混淆影响,或者强制某些部分必须混淆。这样既能保证代码的安全性,也能保持必要的可读性和功能性。
错误堆栈查找
我试了几下,没有找到办法,让显示混淆后的代码的错误堆栈,
https://docs.guardingpearsoftware.com/manual/Obfuscator/Faq.html
恢复设置(没有找到)
是的,要么是没有,要么是没有找到。
相关文章:

Unity_Obfuscator Pro代码混淆工具_学习日志
Unity_Obfuscator Pro代码混淆工具_学习日志 切勿将密码或 API 密钥存储在您附带的应用程序内。 混淆后的热更新暂时没有想到怎么办 Obfuscator 文档 https://docs.guardingpearsoftware.com/manual/Obfuscator/Description.html商店链接Obfuscator Pro(大约$70&a…...

已解决:org.springframework.web.HttpMediaTypeNotAcceptableException
文章目录 写在前面问题描述报错原因分析: 解决思路解决办法1. 确保客户端请求的 Accept 头正确2. 修改 Controller 方法的 produces 参数3. 配置合适的消息转换器4. 检查 Spring 配置中的媒体类型5. 其他解决方案 总结 写在前面 在开发过程中,Spring 框…...

C/C++简单编译原理
我们写的头文件和.cpp文件究竟是如何在电脑中运行的? 先明确几个文件类型: 1、头文件(.h .hpp) 第三方头文件、系统头文件、自编头文件…… 2、编译单位(.cpp .c cu) 自己写的脚本文件 3、目标文件&…...

文件处理不再难:带你轻松攻克C语言文件操作
嘿嘿,家人们,今天咱们来详细剖析C语言中的文件操作,好啦,废话不多讲,开干! 目录 1:为什么使用文件 2:文件的概念 2.1:程序文件 2.2:数据文件 2.3:文件名 3:二进制文件与文本文件 4:文件的打开与关闭 4.1:流与标准流 4.1.1:流 4.1.2:标准流 4.2:文件指针 4.3:文件的…...

Unity3D 单例模式
Unity3D 泛型单例 单例模式 单例模式是一种创建型设计模式,能够保证一个类只有一个实例,提供访问实例的全局节点。 通常会把一些管理类设置成单例,例如 GameManager、UIManager 等,可以很方便地使用这些管理类单例,…...

解析TMalign文本文件中的转换矩阵
TM-align 将两个蛋白质结构通过旋转和位移对齐后: TMalign test1.pdb test2.pdb -m mtx.txt 输出转换矩阵,文件内容为: ------ The rotation matrix to rotate Chain_1 to Chain_2 ------ m t[m] u[m][0] u[…...

vue.js组建开发
Vue.js是一个用于构建用户界面的渐进式JavaScript框架。它采用了组件化的开发方式,将UI界面拆分成多个可重用的组件,通过组合这些组件来构建复杂的应用程序。在本文中,我们将探讨Vue.js组件开发的相关概念和技术。 一、组件化开发的优势 组件…...

D29【python 接口自动化学习】- python基础之输入输出与文件操作
day29 格式化输出 学习日期:20241006 学习目标:输入输出与文件操作﹣-41 格式化输出:如何将执行结果通过屏幕输出? 学习笔记: 三种常用的格式化输出方式 百分号方式 format函数方式 总结 1. 格式化输出…...

jQuery——平滑翻页
平滑翻页 param next true:下一页 false:下一页 本文分享到此结束,欢迎大家评论区相互讨论学习,下一篇继续分享jQuery中循环翻页的学习。...

二叉树--DS
1. 树 1.1 树的定义 树是一种非线性的数据结构,它是由n (n > 0)个有限结点组成的一个具有层次关系的集合。之所以将它称为“树”,是因为它像一颗倒挂起来的树,也就是说它是根朝上,叶子在下的。 参考上面的图片,…...

State of ChatGPT ---- ChatGPT的技术综述
声明:该文总结自AI菩萨Andrej Karpathy在youtube发布的演讲视频。 原视频连接:State of GPT | BRK216HFS 基础知识: Transformer原文带读与代码实现https://blog.csdn.net/m0_62716099/article/details/141289541?spm1001.2014.3001.5501 H…...

构建高效新闻推荐系统:Spring Boot的力量
1系统概述 1.1 研究背景 如今互联网高速发展,网络遍布全球,通过互联网发布的消息能快而方便的传播到世界每个角落,并且互联网上能传播的信息也很广,比如文字、图片、声音、视频等。从而,这种种好处使得互联网成了信息传…...

如何使用ipopt进行非线性约束求目标函数最小值(NLP非线性规划)内点法(inner point method)
非线性规划,一般用matlab调用cplex和gurobi了,但这两个一般用于线性规划和二次规划 线性规划LP,二次规划(quadratic programming),如果要求更一般的非线性规划IPOT是个很好的选择,求解器很多&a…...

【Unity学习笔记】解决疑似升级Win11或使用Unity6导致Unity旧版本无法打开的问题
【Unity学习笔记】解决疑似升级Win11或使用Unity6导致Unity旧版本无法打开的问题 一句话省流: 确保项目地址没有任何中文,重新申请个许可证,然后该咋就咋,完事。 ——————————————————————————————…...

回归分析在数据挖掘中的应用简析
一、引言 在数据驱动的时代,数据挖掘技术已成为从海量数据中提取有价值信息的关键工具。 回归分析,作为一种经典的统计学习方法,不仅在理论研究上有着深厚的基础,而且在实际 应用中也展现出强大的功能。 二、回归分析基础 2.1 回…...

【Node.js】worker_threads 多线程
Node.js 中的 worker_threads 模块 worker_threads 模块是 Node.js 中用于创建多线程处理的工具。 尽管 JavaScript 是单线程的,但有时候在处理计算密集型任务或长时间运行的操作时,单线程的运行会导致主线程被阻塞,影响服务器性能。 为了…...

贪心算法c++
贪心算法C概述 一、贪心算法的基本概念 贪心算法(Greedy Algorithm),又名贪婪法,是一种解决优化问题的常用算法。其基本思想是在问题的每个决策阶段,都选择当前看起来最优的选择,即贪心地做出局部最优的决…...

【STM32】 TCP/IP通信协议(3)--LwIP网络接口
LwIP协议栈支持多种不同的网络接口(网卡),由于网卡是直接跟硬件平台打交道,硬件不同则处理也是不同。那Iwip如何兼容这些不同的网卡呢? LwIP提供统一的接口,底层函数需要用户自行完成,例如网卡的…...

15分钟学 Python 第39天:Python 爬虫入门(五)
Day 39:Python 爬虫入门数据存储概述 在进行网页爬虫时,抓取到的数据需要存储以供后续分析和使用。常见的存储方式包括但不限于: 文件存储(如文本文件、CSV、JSON)数据库存储(如SQLite、MySQL、MongoDB&a…...

使用Pytorch构建自定义层并在模型中使用
使用Pytorch构建自定义层并在模型中使用 继承自nn.Module类,自定义名称为NoisyLinear的线性层,并在新模型定义过程中使用该自定义层。完整代码可以在jupyter nbviewer中在线访问。 import torch import torch.nn as nn from torch.utils.data import T…...

学习记录:js算法(五十六):从前序与中序遍历序列构造二叉树
文章目录 从前序与中序遍历序列构造二叉树我的思路网上思路 总结 从前序与中序遍历序列构造二叉树 给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。 示…...

qt使用QDomDocument读写xml文件
在使用QDomDocument读写xml之前需要在工程文件添加: QT xml 1.生成xml文件 void createXml(QString xmlName) {QFile file(xmlName);if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate |QIODevice::Text))return false;QDomDocument doc;QDomProcessin…...

Oracle架构之表空间详解
文章目录 1 表空间介绍1.1 简介1.2 表空间分类1.2.1 SYSTEM 表空间1.2.2 SYSAUX 表空间1.2.3 UNDO 表空间1.2.4 USERS 表空间 1.3 表空间字典与本地管理1.3.1 字典管理表空间(Dictionary Management Tablespace,DMT)1.3.2 本地管理方式的表空…...

springboot整合seata
一、准备 docker部署seata-server 1.5.2参考:docker安装各个组件的命令 二、springboot集成seata 2.1 引入依赖 <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId>&…...

鸿蒙开发(NEXT/API 12)【二次向用户申请授权】程序访问控制
当应用通过[requestPermissionsFromUser()]拉起弹框[请求用户授权]时,用户拒绝授权。应用将无法再次通过requestPermissionsFromUser拉起弹框,需要用户在系统应用“设置”的界面中,手动授予权限。 在“设置”应用中的路径: 路径…...

docker export/import 和 docker save/load 的区别
Docker export/import 和 docker save/load 都是用于容器和镜像的备份和迁移,但它们有一些关键的区别: docker export/import: export 作用于容器,import 创建镜像导出的是容器的文件系统,不包含镜像的元数据丢失了镜像的层级结构…...

明星周边销售网站开发:SpringBoot技术全解析
1系统概述 1.1 研究背景 如今互联网高速发展,网络遍布全球,通过互联网发布的消息能快而方便的传播到世界每个角落,并且互联网上能传播的信息也很广,比如文字、图片、声音、视频等。从而,这种种好处使得互联网成了信息传…...

STM32+ADC+扫描模式
1 ADC简介 1 ADC(模拟到数字量的桥梁) 2 DAC(数字量到模拟的桥梁),例如:PWM(只有完全导通和断开的状态,无功率损耗的状态) DAC主要用于波形生成(信号发生器和音频解码器) 3 模拟看门狗自动监…...

R语言绘制散点图
散点图是一种在直角坐标系中用数据点直观呈现两个变量之间关系、可检测异常值并探索数据分布的可视化图表。它是一种常用的数据可视化工具,我们通过不同的参数调整和包的使用,可以创建出满足各种需求的散点图。 常用绘制散点图的函数有plot()函数和ggpl…...

安装最新 MySQL 8.0 数据库(教学用)
安装 MySQL 8.0 数据库(教学用) 文章目录 安装 MySQL 8.0 数据库(教学用)前言MySQL历史一、第一步二、下载三、安装四、使用五、语法总结 前言 根据 DB-Engines 网站的数据库流行度排名(2024年)࿰…...