news 2026/9/10 16:45:22

SpringBoot校园外卖系统开发:订单状态机与Redis高并发设计

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringBoot校园外卖系统开发:订单状态机与Redis高并发设计

简介:基于Spring Boot与Vue的校园外卖服务系统设计与实现资料包,面向Java学习者、毕业设计及课程作业场景。系统覆盖管理员端外卖列表、订单状态维护、公告信息发布与公告类型管理等核心功能,其中外卖列表可查看订单号、顾客信息与订单状态,公告管理支持分类发布通知与促销内容;整体采用MySQL数据库与前后端分离架构,配套SQL初始化脚本、完整Java/Vue源码以及安装构建工具,适合需要快速搭建类似系统、完成课程设计或撰写论文的读者。资源共791个文件,包含java后端源码、vue组件、js交互脚本、css样式表,以及xml配置、json数据、gif演示动图、mp4操作视频和少量文档,压缩包约26.52MB,目录结构清晰,便于按模块查阅;内含一键安装、运行、构建脚本,可快速启动项目。已有101人学习下载。通过完整源码及功能模块说明,可掌握Spring Boot整合Vue的项目分层结构、管理员端功能开发思路,同时获得数据库表设计与毕业论文写作的参考素材,对完成毕业设计具有实际帮助。

1. 基于SpringBoot校园外卖服务系统的选题逻辑与落地边界

校园外卖这个毕设题每年都有人选,但多数实现停在了“登录加 CRUD”。真正拉开差距的是订单状态怎么流转、并发下数据怎么保持一致——这恰好是 Spring Boot 生态里最典型的工程场景。系统按四类角色划分:学生下单评价、商户接单出餐、骑手更新配送进度、平台管理员审核资质,天然能把权限模型讲清楚。

选 Spring Boot 的理由直白:内置 Tomcat 让部署只靠 java -jar,MyBatis Plus 和 Spring Data Redis 把集成成本压到最低,源码可读性也适合论文画架构图。Spring Boot 3.x 要求 Java 17,毕设直接以 JDK 17 起步即可。

适合 Java 基础中等、想把毕设做到能演示、能压测、能讲清设计取舍的人群。后面的路径依次是:分层与数据模型、认证与状态机、并发控制、压测排错。

2. SpringBoot校园外卖系统的分层架构与订单数据模型

2.1 Controller-Service-Mapper 分层与请求链路边界

校园外卖后端的分层不复杂,Controller-Service-Mapper 三件套足够覆盖全部模块。真正的坑在于层与层的职责会不自觉越界。见过不少毕设代码里 Controller 里写菜品金额计算、Service 里直接用 HttpSession 取登录用户,短期能跑通,答辩时老师一句“为什么要分这么多层”就答不上来。

我一般会把边界定死:Controller 只做参数接收、参数校验和统一结果包装,不出现任何业务判断;Service 只做业务编排、事务控制和状态校验,不出现 HttpServletRequest、HttpServletResponse 这类 Web 层对象;Mapper 只做数据访问,筛选条件全部用 MyBatis Plus 的 LambdaQueryWrapper 表达。

这套分层的职责边界整理成表,写进论文设计章节可以直接用:

层级职责禁止事项
Controller参数接收、参数校验、结果包装禁止写金额计算、禁止直接操作 Mapper
Service业务编排、事务控制、状态校验禁止出现 Web 层对象
MapperSQL 执行、单表 CRUD、复杂查询禁止包含业务判断

请求从入口到落库的链路是:前端 JSON 到达 Controller,转成 DTO 后调用 Service;Service 内部开启事务,完成数据校验后逐条写入数据库;响应统一返回 Result ,格式固定为 code、message、data 三段。答辩时能徒手画出这条链路,比背十个 Spring 面试题都有效。

2.2 订单主表与明细表的拆分原则、建表 SQL 与自动填充

订单表是这套系统的核心。很多毕设把订单和菜品放同一张表,一个订单三条菜就存三条记录,查详情要按 order_id 分组。正确做法是拆成订单主表和订单明细表:主表保存一次订单的汇总信息,明细表保存每条菜品记录的快照。拆分理由有三条:状态变更只更新主表,明细表只读保持稳定;统计商户营业额聚合主表即可;退款场景下明细表提供可操作的数据粒度。

订单号建议不用自增 ID 暴露给前端,改用时间戳加随机数生成业务订单号,大致格式是 yyyyMMddHHmmss 加 6 位随机数。原因很实际:自增 ID 会把平台当日订单量泄露出去,也方便别人遍历接口。这个细节写进论文里,能体现出对业务安全的考虑。

两张表的核心建表 SQL 放一起看:

CREATE TABLE `orders` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键', `order_no` VARCHAR(32) NOT NULL COMMENT '业务订单号', `user_id` BIGINT NOT NULL COMMENT '用户ID', `merchant_id` BIGINT NOT NULL COMMENT '商户ID', `total_amount` DECIMAL(10,2) NOT NULL COMMENT '订单总金额', `status` TINYINT NOT NULL DEFAULT 0 COMMENT '0待支付1已支付2制作中3配送中4已完成5已取消', `address_detail` VARCHAR(255) NOT NULL COMMENT '配送地址', `remark` VARCHAR(255) DEFAULT NULL COMMENT '备注', `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', KEY `idx_user_id` (`user_id`), KEY `idx_merchant_id` (`merchant_id`), KEY `idx_status` (`status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单主表'; CREATE TABLE `order_item` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键', `order_id` BIGINT NOT NULL COMMENT '订单主表ID', `dish_id` BIGINT NOT NULL COMMENT '菜品ID', `dish_name` VARCHAR(100) NOT NULL COMMENT '菜品名称快照', `price` DECIMAL(10,2) NOT NULL COMMENT '单价快照', `quantity` INT NOT NULL COMMENT '数量', `subtotal` DECIMAL(10,2) NOT NULL COMMENT '小计', KEY `idx_order_id` (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单明细表';

这段 SQL 的逻辑说明:orders 表的 status 用 TINYINT 存数字状态,0 到 5 对应订单生命周期里的六个状态,枚举含义写在注释里,代码里可以用常量类对应;order_item 冗余了 dish_name 和 price 两个字段,这是刻意做快照——菜品改价或下架后,历史订单仍能按当时的价格和名称展示。这个设计点叫“历史数据不可变”,论文里可以单独展开。

注意两张表之间只用索引不用物理外键。高并发写入场景下物理外键每次插入都要做约束检查,拖慢事务;数据一致性交给 Service 层事务控制,由程序保证而不是数据库兜底。

创建时间和更新时间推荐交给 MyBatis Plus 的自动填充处理,不用在每个 Service 方法里手动 set。实现方式是注册一个 MetaObjectHandler:

@Component public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); } @Override public void updateFill(MetaObject metaObject) { this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); } }

这段代码的作用是在实体执行 insert 和 update 时自动写入时间字段。参数说明:第一个参数是实体元数据对象,第二个是字段名,第三个是类型,第四个是填充值。记得在实体字段上加 @TableField(fill = FieldFill.INSERT) 和 @TableField(fill = FieldFill.INSERT_UPDATE),否则填充逻辑不会触发。另外,如果建表 SQL 里 update_time 已经带了 ON UPDATE CURRENT_TIMESTAMP,代码层就不要再用自动填充更新它,两套机制并存会出现时间字段来源不一致的问题,二选一即可。

2.3 四类角色的权限设计与 Spring Security 取舍

校园外卖系统有没有必要引入完整的 Spring Security?我的判断是可以不用。毕设场景下引入 Spring Security 意味着要处理 Filter 链、UserDetailsService、密码加密器等一系列配置,整体调试成本不低。更推荐的方案是自定义拦截器加 JWT,下一章展开实现。

如果论文方向偏工程、需要体现安全设计完整性,用 Spring Security 的 @PreAuthorize 方法级授权也能讲通。取舍的边界在于:自定义拦截器适合角色维度少、细粒度控制需求弱的场景;Spring Security 适合要做按钮级权限、接口权限动态配置的场景。校园外卖的四类角色数量固定且权限边界清晰,自定义方案能省一半时间。角色与权限的关系建议落在数据库菜单表上而不是写死在代码里,管理后台增减权限时不用重新发版。

3. SpringBoot 订单模块的 JWT 登录认证与状态机实现

3.1 JWT Token 生成、拦截器校验与用户上下文传递

登录态方案选择 JWT 的原因很直接:系统同时服务 App 端和 Web 管理后台,服务端不依赖 Cookie,token 放在请求头里就能跨端生效。JWT 分 Header、Payload、Signature 三段,Header 声明算法,Payload 放用户信息,Signature 用密钥做防篡改校验。

Token 生成的工具类可以直接用 jjwt 库:

public class JwtUtil { private static final SecretKey KEY = Keys.hmacShaKeyFor( "campus-order-secret-2026!".getBytes(StandardCharsets.UTF_8)); public static String createToken(Long userId, String role) { return Jwts.builder() .setSubject(String.valueOf(userId)) .claim("role", role) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + 2 * 60 * 60 * 1000L)) .signWith(KEY, SignatureAlgorithm.HS256) .compact(); } public static Claims parseToken(String token) { return Jwts.parserBuilder() .setSigningKey(KEY) .build() .parseClaimsJws(token) .getBody(); } }

代码逻辑说明:createToken 把用户 ID 放进 subject,role 声明里存放角色名,过期时间设为 2 小时;parseToken 负责解析和签名校验,签名不一致会直接抛异常,调用方不需要自己判断。密钥这里写常量只是为了演示,真实项目要放到 application.yml 或环境变量里注入,别让密钥进代码库。

校验链路需要一个拦截器,在请求进入 Controller 之前解析 token:

@Component public class JwtInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { if (!(handler instanceof HandlerMethod)) { return true; } String token = request.getHeader("Authorization"); if (token == null || !token.startsWith("Bearer ")) { throw new BusinessException(401, "未登录或登录态已过期"); } Claims claims = JwtUtil.parseToken(token.substring(7)); UserContext.set(claims.get("userId", Long.class), claims.get("role", String.class)); return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { UserContext.clear(); } }

拦截器逻辑说明:preHandle 里先放行非 HandlerMethod 的请求,比如静态资源;然后从 Authorization 头取 Bearer token,解析成功后把用户信息写入 UserContext。UserContext 背后是一个 ThreadLocal,作用域是当前请求线程。关键在 afterCompletion 必须调用 clear,否则 Tomcat 线程池复用线程时,上一次请求的用户信息会泄漏到下一次请求。

注册拦截器时注意放行规则:登录、注册、菜品浏览接口放行;下单、查询订单、商户管理、骑手接单全部拦截。放行路径按接口前缀配置,比如 /api/auth/** 放行、/api/order/** 拦截。

3.2 订单状态机的合法流转路径与统一校验

订单状态是答辩必问的模块。设计目标只有一个:状态迁移路径要收窄,不能出现平台管理员把订单从已取消改成配送中的操作。六个状态整理成流转表:

当前状态可流转到触发动作
0 待支付1 已支付、5 已取消用户支付 / 用户取消或超时关闭
1 已支付(待接单)2 制作中、5 已取消商户接单 / 退款审核通过
2 制作中3 配送中、5 已取消骑手取餐 / 退款审核通过
3 配送中4 已完成、5 已取消用户确认收货 / 售后处理
4 已完成终态
5 已取消终态

实现上我一般把这张表收敛到一个 Map 里,写一个统一的更新方法:

private static final Map<Integer, List<Integer>> STATUS_FLOW = new HashMap<>(); static { STATUS_FLOW.put(0, Arrays.asList(1, 5)); STATUS_FLOW.put(1, Arrays.asList(2, 5)); STATUS_FLOW.put(2, Arrays.asList(3, 5)); STATUS_FLOW.put(3, Arrays.asList(4, 5)); } public void updateOrderStatus(Long orderId, Integer targetStatus, Long operatorId) { Order order = orderMapper.selectById(orderId); if (order == null) { throw new BusinessException("订单不存在"); } List<Integer> allowed = STATUS_FLOW.get(order.getStatus()); if (allowed == null || !allowed.contains(targetStatus)) { throw new BusinessException("非法状态流转: " + order.getStatus() + " -> " + targetStatus); } order.setStatus(targetStatus); orderMapper.updateById(order); }

这个实现的要点:合法迁移集中在一个静态 Map 里,所有业务方法都走同一个更新入口,不存在某个 Service 方法绕过校验直接改 status 的可能性。参数说明:orderId 定位订单,targetStatus 是目标状态,operatorId 记录操作人用于审计日志。答辩时讲一句“状态机让新增流程只需要改 Map,不需要动业务代码”,设计模式的含金量就有了。

3.3 下单接口幂等性与事务边界控制

下单接口要防重复。用户网络抖动导致请求重试、用户手抖连点两次,没有幂等控制就会产生两笔订单。前端要做按钮置灰,后端也要兜底。兜底方案是幂等键:前端先调预下单接口获取 requestId,下单时携带这个 ID。后端用 Redis 的 SETNX 判断 requestId 是否已处理,已存在则直接返回第一次下单结果。

下单事务的边界要覆盖三件事:插入订单主表、插入订单明细表、扣减菜品库存。三件必须在一个事务里,任何一步失败都回滚。这里有一个容易被忽略的点:扣库存如果是先操作数据库再操作 Redis,事务提交时机和 Redis 操作之间就存在不一致窗口。常见做法是先扣 Redis 库存(返回扣减成功),再执行数据库下单事务,事务失败时补回 Redis 库存。

提示:幂等键在 Redis 里的 TTL 建议设为 10 分钟,覆盖一个完整的下单支付周期就够,设置太长会积累大量无用键。

4. Redis 在校园外卖订单并发场景的三个落点

4.1 菜品库存预扣的 Lua 原子脚本

校园外卖的菜品库存模型是“当日可售份数”:商户每天开店时初始化,卖完即止。用数据库乐观锁做库存扣减能实现,但高并发下 version 条件导致大量更新失败,用户体验差。我一般把库存放进 Redis String 类型,value 是剩余份数,用 Lua 脚本保证检查和扣减的原子性:

-- KEYS[1] = 库存键名, ARGV[1] = 本次扣减数量 local stock = tonumber(redis.call('GET', KEYS[1])) if stock == nil then return -1 end if stock < tonumber(ARGV[1]) then return 0 end redis.call('DECRBY', KEYS[1], ARGV[1]) return 1

脚本含义:GET 读取当前库存,键不存在返回 -1;库存不足返回 0;扣减成功返回 1。Lua 脚本在 Redis 中是原子执行的,整个脚本执行期间不会有其他客户端命令插入,所以“检查库存再扣减”不会被并发请求穿插。

三种库存方案的取舍对比:

方案实现复杂度一致性保证适用场景
数据库乐观锁强(有重试成本)低并发演示
Redisson 分布式锁中高并发
Lua 原子扣减强(无锁等待)高并发下单

Java 侧用 StringRedisTemplate 执行脚本,封装成独立方法:

@Resource private StringRedisTemplate stringRedisTemplate; private static final DefaultRedisScript<Long> DECREASE_STOCK_SCRIPT = new DefaultRedisScript<>( "local stock = tonumber(redis.call('GET', KEYS[1])) if stock == nil then return -1 end if stock < tonumber(ARGV[1]) then return 0 end redis.call('DECRBY', KEYS[1], ARGV[1]) return 1", Long.class ); public int decreaseStock(String key, int count) { Long result = stringRedisTemplate.execute( DECREASE_STOCK_SCRIPT, Collections.singletonList(key), String.valueOf(count) ); return result == null ? -1 : result.intValue(); }

不直接先 GET 再 DECR 的原因:两步操作之间会被并发请求插入——两个请求同时读到剩余 3 份、各扣 2 份,实际扣了 4 份而库存只剩 1 份,超卖就发生了。Lua 脚本把两步合并成一个原子操作,从根上避开问题。执行时注意第一个参数传入 key 列表,第二个参数是可变长的 ARGV,顺序和脚本里的 KEYS[1]、ARGV[1] 一一对应。

库存回滚的时序是另一个坑:Redis 扣减成功、数据库事务回滚时,要调用 INCR 回补库存;反过来先开事务再扣 Redis,Redis 失败时数据库事务已经提交,订单数据就脏了。这个先后顺序建议写成注释放在方法入口,防止后续维护的人改乱。

4.2 菜品列表缓存与缓存穿透空值处理

首页菜品列表是所有用户打开客户端看到的第一个接口,流量远高于其他接口。常见做法是加一层 Redis 缓存,key 设计为 dish:list:{merchantId},value 存菜品 JSON 数组,TTL 设 30 分钟。读取顺序是:先查缓存,命中直接返回;未命中查数据库,再回填缓存。

缓存穿透的场景是恶意请求或测试脚本反复查询不存在的商户 ID。数据库查不到记录,Redis 也不会写入,每个请求都打穿到数据库。毕设项目用布隆过滤器偏重,轻量做法是缓存空值:查询结果为空时也写一条空数组进 Redis,TTL 设 60 秒。这个窗口内的重复穿透请求都落在 Redis 上,数据库压力立刻降下来。代价是极端情况下商户新增菜品后 60 秒内客户端看不到,对毕设演示完全可以接受。

更新策略遵循 Cache Aside Pattern:先更新数据库,再删除缓存。不要先删缓存再更新数据库,否则更新期间会有请求读到旧数据并回填缓存,扩大不一致的窗口。

4.3 超时未支付订单的延迟关闭方案

每日总有用户下单后不支付,这些订单占着库存,必须有自动关闭机制。三套常见方案对比:定时任务每分钟扫数据库,实现简单但有至少一分钟的关闭延迟;Redis 过期事件监听,不可靠且不保证即时;延迟队列用 Redis ZSET 模拟,可控性最好。

具体实现:下单时把订单号作为 member、超时时间戳作为 score 写入 ZSET,另起一个定时任务每秒扫描 score 在当前时间之前的成员:

@Scheduled(fixedDelay = 1000) public void scanExpiredOrders() { long now = System.currentTimeMillis(); Set<String> expired = stringRedisTemplate.opsForZSet() .rangeByScore(ORDER_TIMEOUT_KEY, 0, now); if (expired == null || expired.isEmpty()) { return; } for (String orderNo : expired) { boolean closed = closeIfUnpaid(orderNo); if (closed) { stringRedisTemplate.opsForZSet().remove(ORDER_TIMEOUT_KEY, orderNo); } } }

这段逻辑的说明:rangeByScore(0, now) 取出所有超时订单号;closeIfUnpaid 里先查数据库确认状态还是待支付,满足条件才改成已取消并回补 Redis 库存;处理成功的成员从 ZSET 中移除避免重复扫描。这里的关键原则是 Redis 只负责提醒“该检查了”,最终状态以数据库为准。

5. 答辩前的 JMeter 压测与 SpringBoot 高频坑位排查

5.1 200 并发下单的 JMeter 压测方法与指标解读

答辩最怕被问“系统能扛多少并发”。用 JMeter 提前给出一组数据,底气完全不同。配置方式是:线程组里设 200 个线程、Ramp-Up 5 秒、循环次数 10。HTTP 请求指向下单接口,Header 里加 Authorization 的 Bearer Token,token 用前置处理器从登录接口动态获取,避免所有请求共用同一个 token。

压测重点读三个指标:平均响应时间在 500ms 内合格;错误率必须为 0;吞吐量按请求总数除以总耗时估算,200 用户乘 10 次循环、耗时 30 秒左右,大致对应 60 到 70 的 TPS。这个数据写进论文测试章节,足够支撑“系统满足校园高峰期 200 人同时下单”的结论。

5.2 高并发场景的排查顺序

压测出现报错时按三层顺序排查:第一看日志有没有 HikariCP 连接池满的异常,默认最大连接数 10,200 并发下单瞬间就打满;第二看锁等待超时,订单状态更新是行锁操作,并发高时出现 Lock wait timeout exceeded,就把事务里非必要查询挪到事务外;第三看 Redis 连接池,Lettuce 连接池耗尽的表现是 RedisConnectionFailureException。

这三条路径基本覆盖了毕设系统压测失败的大部分场景。先调大连接池再观察,最后才考虑代码级优化,别一上来就改业务逻辑。

5.3 高频报错对照与缓存命中率自检

把做这个题目最容易踩的四个 SpringBoot 集成问题整理成对照表,排错时直接定位:

现象根因处理方式
LocalDateTime 序列化成数组,前端 JSON 格式不对Jackson 对 Java 8 时间类型默认序列化不友好@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 或全局配置 jackson.date-format
连接 MySQL 报 Unknown database 或时区异常JDBC 缺时区参数URL 加 serverTimezone=Asia/Shanghai,库字符集设 utf8mb4
项目启动报循环依赖错误Spring Boot 2.6 起默认禁止循环依赖把公共逻辑下沉到独立 Service,消除互相注入
订单列表数据过万后页面变慢查询没走索引或缺联合索引EXPLAIN 看执行计划,确认 user_id + status 命中组合索引

压测之外值得做的一个验证:在 Redis 客户端里执行 INFO stats,看 keyspace_hits 和 keyspace_misses 两个指标。缓存命中率低于 60% 说明 key 设计或 TTL 设置有问题,可能是菜品更新时删缓存太频繁,也可能是 TTL 太短导致缓存频繁重建。把命中率数据记录到论文测试章节,比贴十张界面截图都有说服力。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 16:45:09

Vue3响应式系统:ref与reactive核心解析与实战指南

1. Vue3 响应式系统设计哲学Vue3 的响应式系统是其核心机制&#xff0c;它通过 Proxy API 实现了比 Vue2 更高效、更灵活的响应式追踪。与 Vue2 基于 Object.defineProperty 的实现相比&#xff0c;Proxy 能够捕获对象的所有操作&#xff08;包括属性添加/删除&#xff09;&…

作者头像 李华
网站建设 2026/9/10 16:43:42

2026saas建站平台有哪些?四家中小企业值得合作的建站公司盘点!

2026年SaaS建站平台有哪些&#xff1f;四家中小企业值得合作的建站公司盘点&#xff01;IDC发布的《2025年中国中小企业数字化服务市场跟踪报告》显示&#xff0c;2025年国内中小企业SaaS建站市场规模同比增长22.9%&#xff0c;零代码、低代码建站工具的市场渗透率已突破43%。工…

作者头像 李华
网站建设 2026/9/10 16:43:37

哪家小程序开发工具性价比最高?想要不踩坑的可以看看这几个!

哪家小程序开发工具性价比最高&#xff1f;想要不踩坑的可以看看这几个&#xff01;中国信通院《2026年中小企业数字化工具应用白皮书》显示&#xff0c;当前国内超62%的中小企业将小程序作为线上经营的核心载体&#xff0c;“性价比”与“易用性”连续三年位列商家选型决策因素…

作者头像 李华
网站建设 2026/9/10 16:42:38

CANN/ge图引擎API:获取控制输出节点

GetOutControlNodes 【免费下载链接】ge GE&#xff08;Graph Engine&#xff09;是面向昇腾的图编译器和执行器&#xff0c;提供了计算图优化、多流并行、内存复用和模型下沉等技术手段&#xff0c;加速模型执行效率&#xff0c;减少模型内存占用。 GE 提供对 PyTorch、Tensor…

作者头像 李华