Mabitys总结
一、ORM
ORM(Object/Relation Mapping),中文名称:对象/关系 映射。是一种解决数据库发展和面向对象编程语言发展不匹配问题而出现的技术。
使用JDBC技术时,手动实现ORM映射:

使用ORM时,自动关系映射:
(1)ORM的具体实现可以认为是一个整体。
(2)SQL执行结果后,如果执行的是增删改,不需要去编写拆卸对象的代码,而是由ORM把对象中属性值取出放入到SQL中。
(3)SQL执行结果后,如果执行的是查询,会由ORM将数据库中查询到的结果,转换为对象。
(4)ORM技术相当于一个转换器,是面向对象语言和数据库之间的纽带。
(5)ORM框架封装了对象/关系的自动映射。

MyBatis:目前使用最多的ORM框架。
二、Mybatis中的SQL语句中的参数
1.MyBatis中最常用的占位符为 #{}。
1.SQL语句中使用#{}获取Test类中传递过来的参数值。
2. 当参数对象类型时,可以使用#{对象中属性名}获取对象属性值。
2.${} 的使用
${}在被MyBatis进行解析时,不会解析为占位符,而是直接解析成对应的值。也就是说使用${}时有点类似字符串拼接,会有SQL注入问题。 但是使用${}可以动态设置列名或表名。
3.#{}和${}的区别(经典面试题)
#{}被解析为?,用在设置列的值或条件值时,也可以使用在分页等需要设置具体值的情况。
${}表示字符串拼接,用在动态设置表名和动态设置列名的情况下。
三、MyBatis中DQL操作
yBatis的DQL操作在映射文件都是通过<select>标签实现的。
SqlSession根据根据查询结果类型不同,提供了五种查询方法:
| 方法名 | 解释说明 |
|---|---|
| selectOne() | 查询一行数据时,返回值为Object。如果没有查询到,返回为nill,但是不能查询到多行。 |
| selectMap() | 查询多行数据时,把其中某列结果当做key,每行结果为Value。 |
| selectList() | 当查询多行数据时,返回值为List。如果没有查询到返回长度为零的List对象。 |
| selectCursor() | 使用游标查询时使用,在大量数据时可以代替分页。 |
| select() | 万能方法,需要自己定义结果处理器 |
四、SQL查询结果填充的几种方式(面试题)
1. 介绍
MyBatis会根据句映射关系把查询到的结果填充到指定结果集类型中。支持方式:
-
auto mapping:自动映射。当列名或列的别名与实体类属性名相同时不需要做额外配置。
-
resultMap:手动定义映射关系。
-
camel case:驼峰命名规则。
2. 驼峰转换
MyBatis提供了驼峰转换的能力。通过全局配置文件开启驼峰转换功能后,就可以让xxx_yyy自动映射到xxxYyy上。例如:列名叫做peo_id,可以自动映射到peoId的属性上。转换时去掉列中的下划线,把下划线后面单词首字母变大写。
五、接口绑定方案
MyBatis提供了一种接口绑定方案,通过SqlSession的getMapper方法产生接口的动态代理对象。然后通过对象调用接口中提供的功能。
1.接口绑定方案中映射文件的要求
在接口绑定方案中,对于映射文件有几点强制要求:
映射文件和接口需要在同一个包中
映射文件名称要和接口名称相同
namespace取值必须是接口的全限定路径
id属性值必须和方法名对应
resultType必须和方法返回值类型对应。如果方法返回值是集合类型,resultType中写泛型的类型
2.接口绑定方案下参数传递
| 接口中方法 | SqlSession的方法 |
|---|---|
| int insertPeople(People peo); | session.insert("insertPeople",peo); |
| int deleteById(int id); | session.delete("deleteById",id); |
| int updatePeople(People peo); | session.update("updatePeople",peo); |
| People selectById(int id); | session.selectOne("selectById",id); |
| List<People> selectAll(); | session.selectList("selectAll"); |
| List<People> selectByUnameAndAddr(String name,String address); | session.selectList("selectByUnameAndAddr",Map类型参数) |
当方法带有多个参数将使用session.selectList("",Map类型参数)或session.selectOne("",Map类型参数)作为底层调用。
Mybatis会自动创建Map的key:
如果接口中方法没有使用注解定义名称,MyBatis使用内置名称作为key。
规则:arg0、arg1、argM(M为从0开始的数字,和方法参数顺序对应)或param1、param2、paramN(N为从1开始的数字,和方法参数顺序对应)。
也可以在接口方法参数中通过@Param("key名称")的形式进行定义key。一定使用了注解argN的这种形式就不能使用了,但是paramN的方式还是可以使用。
六、动态SQL
1. if标签
通过if处理用户多变的查询条件。类似于:
if(){} if(){}
<if>标签的test属性值为OGNL(对象导航图语言)表达式,通过对象属性名可以快速获取到对象属性值。
2. choose
- choose标签相当于Java中的if...else if....else。
- 在choose标签里面可以有多个when标签和一个otherwise(可以省略)标签。
- 只要里面有一个when成立了后面的when和otherwise就不执行了。
3. trim标签
trim标签包含四个属性:
- prefix:子内容不是空字符串(""),就在子内容前面添加特定字符串。
- prefixOverrides:子内容是以某个内容开头,去掉这个内容。
- suffix:子内容不是空字符串(""),就在子内容后面添加特定字符串。
- suffixOverrides:子内容以某个内容结尾,就去掉这个内容。
trim只会对里面的子内容进行操作。如果子内容为空则不进行任何操作。后添加的内容会有空格。
特例:
如果内部字符串为要去掉的字符串,去掉后认为内容不为空,prefix依然添加。
4. where标签
where标签属于trim标签的简化版,被where标签包含的内容具备:
如果里面内容不为空串,在里面内容最前面添加where。
如果里面内容是以and开头,去掉最前面的and。
5. set标签
set标签是专门用在修改SQL中的,属于trim的简化版,带有下面功能:
如果子内容不为空串,在最前面添加set。
去掉最后一个逗号。
6. foreach标签
foreach标签表示循环,主要用在in查询或批量新增的情况。
foreach标签的属性解释说明:
- collection:要遍历的数组或集合对象。(如果参数没有使用@Param注解:arg0或array或list。. 如果使用@Param注解,使用注解的名称或param1。 )
- open:遍历结束在前面添加的字符串。
- close:遍历结束在后面添加的字符串。
- item:迭代变量。在foreach标签里面#{迭代变量}获取到循环过程中迭代变量的值。
- separator:分隔符。在每次循环中间添加的分割字符串。
- index:迭代的索引。从0开始的数字。
- nullable:是否允许数组或集合对象为null。如果设置为true,表示集合或数组允许为null。如果设置为false表示不允许数组或集合对象为null,一旦为null会出现异常。
7. bind标签(拼接使用)
bind标签表示对传递进来的参数重新赋值。最多的使用场景为模糊查询。通过bind可以不用在Java代码中对属性添加%。
8. sql和include标签
MyBatis的sql标签用于定义SQL片段,include标签用于引用sql标签定义的片段。
七、MyBatis中常用注解
八、多表查询(面试题)
1. 介绍
- 在学习MyBatis多表查询时其实就是在学习
<association>标签和<collection>标签。1.如果一个实体类关联另一个实体类的一个对象使用
<association>。2.如果一个实体类关联一个实体类的List集合对象,需要使用
<collection>。
- 这两个标签根据编写的SQL,分为N+1查询和联合查询两种方式。
2. 联合查询方式
<mapper namespace="com.bjsxt.mapper.EmpMapper"><!-- 每行数据最终返回的是Emp对象 --><resultMap id="empMap" type="Emp"><id column="e_id" property="id"/><result column="e_name" property="name"/><!-- 单个对象类型属性,使用association进行填充 --><!-- property:对象名 javaType:对象类型,支持别名--><association property="dept" javaType="Dept"><!-- 对属性对象里面的属性配置映射关系 --><id column="d_id" property="id"/><result column="d_name" property="name"/></association></resultMap><!-- 使用resultMap配置结果集映射 --><select id="seletAll" resultMap="empMap">select d_id,d_name,e_id,e_name,e_d_id from dept d,emp e where d.d_id=e.e_d_id</select>
</mapper>
3. N+1查询方式
N+1查询方式命名由来:当查询Emp表中N条数据时,需要编写1条查询全部的SQL和N条根据外键列值作为另一张表主键查询条件的N条SQL语句。
<resultMap id="deptMap2" type="Dept"><id column="d_id" property="id"></id><result column="d_name" property="name"></result>
</resultMap>
<select id="selectById" resultMap="deptMap2">select * from dept where d_id=#{id}
</select><resultMap id="empMap2" type="Emp"><id column="e_id" property="id"/><result column="e_name" property="name"/><!-- 此处依然使用association填充单个对象属性值.property和javaTye依然需要写 --><!-- select 调用另一个查询的路径,同一个映射文件中,前面namespace可以省略--><!-- column: 当前SQL查询结果哪个列值当做参数传递过去。如果是多个参数{"key":column,"key2":column2}--><association property="dept" javaType="Dept" select="com.bjsxt.mapper.DeptMapper.selectById" column="e_d_id"></association>
</resultMap><select id="selectAllN1" resultMap="empMap2">select e_id,e_name,e_d_id from emp
</select>
九、延迟加载(面试题)
延迟加载只能出现在多表联合查询的N+1方式中。表示当执行当前方法时,是否立即执行关联方法的SQL。
配置延迟加载:
全局配置。整个项目所有N+1位置都生效。
局部配置。只配置某个N+1位置。
两种方式需要选择其中一种,如果两种方式都使用了,局部配置方式生效。
1.全局配置方式
<settings><setting name="lazyLoadingEnabled" value="true"/>
</settings>
2.局部配置方式
局部配置方式需要在collection或association标签中配置fetchType属性。fetchType可取值:lazy(延迟加载)和earge(立即加载)。
当配置了fetchType属性后,全局settings的配置被覆盖,对于当前标签以fetchType属性值为准。
十、缓存(面试题)
1. 缓存介绍
MyBatis的缓存将相同查询条件的SQL语句执行一遍后所得到的结果存在内存或者某种缓存介质当中,当下次遇到一模一样的查询SQL时候不在执行SQL与数据库交互,而是直接从缓存中获取结果。
MyBatis分为一级缓存和二级缓存,同时也可配置关于缓存设置。
一级存储是SqlSession上的缓存。
二级缓存是在SqlSessionFactory(namespace)上的缓存。
默认情况下,MyBatis开启一级缓存,没有开启二级缓存。当数据量大的时候可以借助一些第三方缓存框架或Redis缓存来协助保存Mybatis的二级缓存数据。
2. 一级缓存
一级缓存想要生效,必须同时满足3个条件:
1. 同一个SqlSession对象。
2. 同一个select标签。本质为底层同一个JDBC的Statemen对象。
3. 完全相同的SQL,包含SQL的参数值也必须相同。
4. insert、delete、update操作会清空一级缓存数据。
5. close(),commit也会清空缓存。
2.1 一级缓存流程图
命中缓存:从Map中查询是否存在指定key。如果存在表示命中缓存,如果不存在这个key,需要访问数据库。
更新到缓存:把查询结果put到map中。

3. 二级缓存
3.1 二级缓存介绍
二级缓存是以namespace为标记的缓存,可能要借助磁盘,磁盘上的缓存,可以由一个SqlSessionFactory创建的SqlSession之间共享缓存数据,默认并不开启。
二级缓存生效条件:
同一个SqlSessionFactory对象。
同一个方法(<select>)。
SQL完全相同
重要提示:
二级缓存默认不开启,需要手动开启。只有当SqlSession执行commit或close时才会存储到二级缓存中。

3.2 配置二级缓存生效
1.全局开关:在mybatis.xml文件中的<settings>标签配置开启二级缓存。
<settings><setting name="cacheEnabled" value="true"/>
</settings>
2.分开关:在要开启二级缓存的mapper文件中开启缓存。使用<cache/>配置时,注解的查询无法缓存。
-
<mapper namespace="com.bjsxt.mapper.EmpMapper"><cache/> </mapper>
3.二级缓存未必完全使用内存,有可能占用硬盘存储,缓存中存储的JavaBean对象必须实现序列化接口
public class Dept implements Serializable { }
4.重要总结
-
查询数据顺序 二级-->一级--->数据库--->把数据保存到一级 --->把数据保存到二级(临时),当sqlsession关闭或者提交的时候,把数据刷新到二级缓存(非临时)中。
-
执行了DML操作、close()、commit() ,会清空一级缓存,所以数据变更不可能到达二级缓存中。
十一、四大核心接口介绍及执行流程(面试题)
1. 四大核心接口介绍
-
Executor执行器,执行器负责整个SQL执行过程的总体控制。默认SimpleExecutor执行器。
-
StatementHandler语句处理器,语句处理器负责和JDBC层具体交互,包括prepare语句,执行语句,以及调用ParameterHandler.parameterize()。默认是PreparedStatementHandler。
-
ParameterHandler参数处理器,参数处理器,负责PreparedStatement入参的具体设置。默认使用DefaultParameterHandler。
-
ResultSetHandler结果集处理器,结果处理器负责将JDBC查询结果映射到java对象。默认使用DefaultResultSetHandler。

2. 执行顺序

(1)使用执行器Executor控制整个执行流程
(2)实例化StatementHandler,进行SQL预处理
(3)使用ParameterHandler设置参数
(4)使用StatementHandler执行SQL
(5)使用ResultSetHandler处理结果集
3.Executor执行器类型(面试题)

-
BaseExecutor:主要是使用了模板设计模式,共性被封装在 BaseExecutor 中,容易变化的内容被分离到了子类中 。
-
SimpleExecutor:默认的执行器类型。每次执行query和update(DML)都会重新创建Statement对象。
-
ReuseExecutor:执行器会重用预处理语句。不会每一次调用都去创建一个新的 Statement 对象,而是会重复利用以前创建好的(如果SQL相同的话)。
-
BatchExecutor:用在update(DML)操作中。所有SQL一次性提交。适用于批量操作。
-
-
CachingExecutor:处理缓存的执行器。无论使用上面三种执行器中的哪个。都是会执行CachingExecutor。
十二、MyBatis执行原理详解(较常见面试题)
- 首先加载全局配置文件为输入流,交给XPathParser解析器解析为Document文档对象,然后使用DOM解析Document文档对象,把解析结果存放在Configuration配置类中。
- 通过DefaultSqlSessionFactory实例化工厂,实例SqlSession的对象。创建了SqlSession接口的实现类DefaultSqlSession对象,在创建过程中,会同时创建Transaction事务对象、Executor执行器对象。如果当前项目有Interceptor拦截器,创建执行器时会执行拦截器。
- 通过JDK提供的Proxy创建接口的动态代理对象。
- 可以通过接口的代理对象调用方法。在调用方法时MyBatis会根据方法的类型判断调用SqlSession的哪个方法。例如:selectList、selectOne、update、insert等。
- 确定好具体调用SqlSession的哪个方法后,会按照执行器类型执行MyBatis四大核心接口,执行时也会触发拦截器Interceptor。最终会返回SQL的执行结果。
- 执行完方法后需要提交事务,提交时清空缓存、清除存储的Statement对象。
- 最后关闭SqlSession对象,释放资源。
相关文章:
Mabitys总结
一、ORM ORM(Object/Relation Mapping),中文名称:对象/关系 映射。是一种解决数据库发展和面向对象编程语言发展不匹配问题而出现的技术。 使用JDBC技术时,手动实现ORM映射: 使用ORM时,自动关系映射: &am…...
JAVA安全之Log4j-Jndi注入原理以及利用方式
什么是JNDI? JDNI(Java Naming and Directory Interface)是Java命名和目录接口,它提供了统一的访问命名和目录服务的API。 JDNI主要通过JNDI SPI(Service Provider Interface)规范来实现,该规…...
Spring源码系列-框架中的设计模式
简单工厂 实现方式: BeanFactory。Spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象,但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定。 实质: 由一个工厂…...
数据的读取和保存-MATLAB
1 序言 在进行数据处理时,经常需要写代码对保存在文件中的数据进行读取→处理→保存的操作,流程图如下: 笔者每次在进行上述操作时,都需要百度如何“选中目标文件”以及如何“将处理好的数据保存到目标文件中”,对这一…...
C++ 输入、输出和整数运算
【问题描述】 编写一个程序,读入两个整数,计算并输出他们的和、积、商和余数。 【输入形式】 程序运行到输入时,不要显示输入提示信息。 输入为两个整数(在问题描述中记作A和B,程序中请自定变量名),A和B使…...
Element Plus 解决组件显示英文问题
要解决Element Plus日历组件显示英文的问题,可以使用Element Plus提供的国际化功能,切换成中文语言。下面是一个简单的示例: 首先,在main.ts或者你的入口文件中引入Element Plus的中文语言包和Vue I18n: import { cr…...
sqlite3.NotSupportedError: deterministic=True requires SQLite 3.8.3 or higher
问题描述 sqlite3.NotSupportedError: deterministicTrue requires SQLite 3.8.3 or higher 解决方法 A kind of solution is changing the database from sqlite3 to pysqlite3. After acticate the virtualenv, install pysqlite. pip3 install pysqlite3 pip3 install …...
单线程介绍、ECMAScript介绍、操作系统Windows、Linux 和 macOS
目录 单线程介绍ECMAScript介绍操作系统Windows、Linux 和 macOS 👍 点赞,你的认可是我创作的动力! ⭐️ 收藏,你的青睐是我努力的方向! ✏️ 评论,你的意见是我进步的财富! 单线程介绍 单线…...
【Docker】iptables基本原理
在当今数字化时代,网络安全问题变得越来越重要。为了保护我们的网络免受恶意攻击和未经授权的访问,我们需要使用一些工具来加强网络的安全性。其中,iptables是一个强大而受欢迎的防火墙工具,它可以帮助我们控制网络流量并保护网络…...
微服务架构——笔记(3)Eureka
微服务架构——笔记(3) 基于分布式的微服务架构 本次笔记为 此次项目的记录,便于整理思路,仅供参考,笔者也将会让程序更加完善 内容包括:1.支付模块、2.消费者订单模块、支付微服务入驻Eureka、Eureka集群…...
网络编程套接字(2)——简单的TCP网络程序
文章目录 一.简单的TCP网络程序1.服务端创建套接字2.服务端绑定3.服务端监听4.服务端获取连接5.服务端处理请求6.客户端创建套接字7.客户端连接服务器8.客户端发起请求9.服务器测试10.单执行流服务器的弊端 二.多进程版的TCP网络程序1.捕捉SIGCHLD信号2.让孙子进程提供服务 三.…...
MySQL数据库的简单的面试题
1、MySQL有哪些锁机制 MySQL有以下几种机制: 行级锁:行极锁在mysql 中最常用的锁机制,它只针对表的某一行进行加锁不受影响。MySQL的行级锁分为共享锁和排他锁两种类型,共享锁和排它锁不能同时存在于一行。 表级锁:表…...
hbuilderx打包应用上传到app store构建版本的教程
简介: 将ipa上架app store的过程中,发现需要将打包的ipa文件上传到app store的构建版本里,但是苹果官方推荐的上传工具,只有xcode和transporter等工具,这些工具是不能安装在windows电脑的。那么有没有windows电脑的上传…...
第五届泰迪杯数据分析技能赛B题源码图片分享
需要B题源码以及第六届带队”指导“请私信本人,团队包含技能赛双一等,数学建模省一,泰迪杯挖掘国一,研究生队友。 去年一等作品可视化图如下,私信获取源码...
【小白专用】VSCode下载和安装与配置PHP开发环境(详细版) 23.11.08
1. 下载VSCode2. 解决VSCode下载速度特别慢3. 安装VSCode 一、VSCode介绍 VSCode 是一款由微软开发且跨平台的免费源代码编辑器;该软件支持语法高亮、代码自动补全、代码重构、查看定义功能,并且内置了命令行工具和 Git 版本控制系统。 二、官方下载地址…...
Qlik Sense : Fetching data with Qlik Web Connectors
目录 Connecting to data sources Opening a connector Connecting to a data source Authenticating the connector Defining table parameters Using standard mode or legacy mode Standard mode Connector overview Using multi-line input parameters to fetch da…...
聊一聊 tcp/ip 在.NET故障分析的重要性
一:背景 1. 讲故事 这段时间分析了几个和网络故障有关的.NET程序之后,真的越来越体会到计算机基础课的重要,比如 计算机网络 课,如果没有对 tcpip协议 的深刻理解,解决这些问题真的很难,因为你只能在高层做…...
利用梯度上升可视化卷积核:基于torch实现
利用梯度上升可视化卷积核 文章目录 前言基本原理版本和包结果展示 简单绘图修改源码绘图方法一 方法二(推荐) 报错解决总结 前言 基于梯度上升的可视化是一种常用的技术,用于理解卷积神经网络(CNN)中的卷积核是如何对…...
python+playwright 学习-85 启动参数 proxy 设置代理几种方式
前言 在使用playwright执行代码的时候,如需设置代理,可以在启动的时候加proxy 参数设置代理。 本篇总结下可以加proxy代理的几种方式。 launch 启动全局代理 launch 启动的时候设置全局代理,以下是示例 from playwright.sync_api import Playwright, sync_playwrightwit…...
Clion 搭建Qt projects
Qt projects Qt is a cross-platform C framework for creating GUI applications. Qt uses its own build system, qmake, and also supports building with CMake starting from the version Qt4. Qt是一款创建桌面程序的跨平台的C框架。qmake是Qt自有的构建系统࿰…...
论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...
基于SpringBoot在线拍卖系统的设计和实现
摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统,主要的模块包括管理员;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
CppCon 2015 学习:Time Programming Fundamentals
Civil Time 公历时间 特点: 共 6 个字段: Year(年)Month(月)Day(日)Hour(小时)Minute(分钟)Second(秒) 表示…...
【免费数据】2005-2019年我国272个地级市的旅游竞争力多指标数据(33个指标)
旅游业是一个城市的重要产业构成。旅游竞争力是一个城市竞争力的重要构成部分。一个城市的旅游竞争力反映了其在旅游市场竞争中的比较优势。 今日我们分享的是2005-2019年我国272个地级市的旅游竞争力多指标数据!该数据集源自2025年4月发表于《地理学报》的论文成果…...
Mac flutter环境搭建
一、下载flutter sdk 制作 Android 应用 | Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 1、查看mac电脑处理器选择sdk 2、解压 unzip ~/Downloads/flutter_macos_arm64_3.32.2-stable.zip \ -d ~/development/ 3、添加环境变量 命令行打开配置环境变量文件 ope…...
