【6.1.2 漫画分布式事务技术选型】

漫画分布式事务技术选型

🎯 学习目标:掌握架构师核心技能——分布式事务技术选型与一致性解决方案,构建高可靠的分布式系统


🎭 第一章:分布式事务模式对比

🤔 2PC vs 3PC vs TCC vs Saga

想象分布式事务就像不同的团队协作方式…

🎭 分布式事务协作模式:2PC (二阶段提交):
┌─────────────────────────────────────┐
│        协调者 (Coordinator)          │
│              │                      │
│    ┌─────────┼─────────┐            │
│    ▼         ▼         ▼            │
│ 参与者A   参与者B   参与者C          │
│ (准备)    (准备)    (准备)           │
│    │         │         │            │
│    ▼         ▼         ▼            │
│ (提交)    (提交)    (提交)           │
│                                    │
│ 特点:                              │
│ • 强一致性保证                      │
│ • 阻塞性问题                        │
│ • 单点故障风险                      │
│ • 适用:小规模关键业务              │
└─────────────────────────────────────┘TCC (Try-Confirm-Cancel):
┌─────────────────────────────────────┐
│           业务活动管理器             │
│              │                      │
│    ┌─────────┼─────────┐            │
│    ▼         ▼         ▼            │
│ 服务A-Try 服务B-Try 服务C-Try       │
│ (资源预留) (资源预留) (资源预留)     │
│    │         │         │            │
│    ▼         ▼         ▼            │
│ Confirm   Confirm   Confirm         │
│ (确认)    (确认)    (确认)           │
│                                    │
│ 特点:                              │
│ • 业务侵入性强                      │
│ • 最终一致性                        │
│ • 性能较好                          │
│ • 适用:业务可拆分场景              │
└─────────────────────────────────────┘Saga (长事务):
┌─────────────────────────────────────┐
│          Saga编排器                  │
│              │                      │
│    T1 → T2 → T3 → T4 → T5           │
│    │    │    │    │    │            │
│   C1 ← C2 ← C3 ← C4 ← C5            │
│ (事务)              (补偿)           │
│                                    │
│ 特点:                              │
│ • 长事务友好                        │
│ • 业务补偿逻辑                      │
│ • 最终一致性                        │
│ • 适用:复杂业务流程                │
└─────────────────────────────────────┘

📊 分布式事务技术详细对比

📊 分布式事务技术对比:┌─────────────┬─────────────┬─────────────┬─────────────┐
│    特性     │     2PC     │     TCC     │    Saga     │
├─────────────┼─────────────┼─────────────┼─────────────┤
│ 🔒 一致性   │    强一致    │   最终一致   │   最终一致   │
│ 🚀 性能     │     低      │     中      │     高      │
│ 🔧 复杂度   │    简单     │     高      │     中      │
│ 📊 吞吐量   │     低      │     中      │     高      │
│ 🛡️ 可靠性   │    中等     │     高      │     高      │
│ 💻 业务侵入 │     小      │     大      │     中      │
│ 🌐 适用场景 │  关键业务    │  核心交易    │  复杂流程   │
│ 🎯 推荐度   │     低      │     高      │     高      │
└─────────────┴─────────────┴─────────────┴─────────────┘技术选型建议:
🎯 银行转账系统 → TCC (资金安全)
🎯 电商下单流程 → Saga (流程复杂)
🎯 库存扣减场景 → TCC (原子操作)
🎯 数据同步任务 → Saga (长时间运行)
🎯 支付系统 → TCC (强一致性要求)

🎯 分布式事务选型决策树

🎯 分布式事务选型流程:开始选型│┌────▼────┐│一致性要求│└────┬────┘│┌──────────────┼──────────────┐▼              ▼              ▼强一致性       最终一致性      高性能要求│              │              │┌────▼────┐    ┌────▼────┐    ┌────▼────┐│关键业务  │    │复杂流程  │    │高并发   │└────┬────┘    └────┬────┘    └────┬────┘│              │              │▼              ▼              ▼XA/2PC事务      Saga模式        异步消息(小规模场景)    (长事务场景)     (最终一致)重要业务场景选型:
┌─────────────────┬─────────────┬─────────────┐
│   业务场景       │  推荐方案    │   备选方案   │
├─────────────────┼─────────────┼─────────────┤
│ 银行转账         │    TCC      │    XA       │
│ 电商下单         │   Saga      │   本地消息表 │
│ 库存扣减         │    TCC      │   分布式锁   │
│ 订单支付         │    TCC      │    2PC      │
│ 数据同步         │   Saga      │   消息队列   │
│ 批量处理         │   Saga      │   状态机    │
└─────────────────┴─────────────┴─────────────┘

🛠️ 第二章:Seata分布式事务框架

🏗️ Seata架构与模式

// 🛠️ Seata分布式事务实战/*** Seata配置中心*/
@Configuration
@EnableAutoDataSourceProxy
public class SeataConfig {/*** AT模式数据源代理*/@Bean@Primarypublic DataSourceProxy dataSourceProxy(DataSource dataSource) {return new DataSourceProxy(dataSource);}/*** TCC模式业务资源管理器*/@Beanpublic TccTransactionManager tccTransactionManager() {return new TccTransactionManager();}/*** Saga状态机配置*/@Beanpublic StateMachineEngine stateMachineEngine() {StateMachineEngineBuilder builder = StateMachineEngineBuilder.newBuilder();builder.setDataSource(dataSource()).setTransactionManager(platformTransactionManager()).setApplicationContext(applicationContext);return builder.build();}
}/*** AT模式 - 自动补偿*/
@Service
@Slf4j
public class OrderServiceAT {@Autowiredprivate OrderRepository orderRepository;@Autowiredprivate AccountServiceClient accountServiceClient;@Autowiredprivate ProductServiceClient productServiceClient;/*** 创建订单 - AT模式全局事务*/@GlobalTransactional(name = "create-order", rollbackFor = Exception.class)public Order createOrder(CreateOrderRequest request) {log.info("开始创建订单: userId={}", request.getUserId());try {// 1. 创建订单记录Order order = new Order();order.setUserId(request.getUserId());order.setProductId(request.getProductId());order.setQuantity(request.getQuantity());order.setAmount(request.getAmount());order.setStatus(OrderStatus.PENDING);order.setCreateTime(LocalDateTime.now());order = orderRepository.save(order);log.info("订单创建成功: orderId={}", order.getId());// 2. 扣减账户余额accountServiceClient.deductBalance(request.getUserId(), request.getAmount());log.info("账户扣款成功: userId={}, amount={}", request.getUserId(), request.getAmount());// 3. 扣减商品库存productServiceClient.reduceStock(request.getProductId(), request.getQuantity());log.info("库存扣减成功: productId={}, quantity={}", request.getProductId(), request.getQuantity());// 4. 更新订单状态order.setStatus(OrderStatus.SUCCESS);orderRepository.save(order);log.info("订单处理完成: orderId={}", order.getId());return order;} catch (Exception e) {log.error("订单创建失败: userId={}", request.getUserId(), e);throw new OrderException("订单创建失败: " + e.getMessage(), e);}}
}/*** TCC模式 - 手动补偿*/
@LocalTCC
@Service
@Slf4j
public class AccountServiceTCC {@Autowiredprivate AccountRepository accountRepository;@Autowiredprivate AccountFreezeRepository freezeRepository;/*** Try阶段 - 冻结资金*/@TwoPhaseBusinessAction(name = "deductBalance",commitMethod = "confirmDeduct",rollbackMethod = "cancelDeduct")public boolean deductBalance(BusinessActionContext context,@BusinessActionContextParameter("userId") Long userId,@BusinessActionContextParameter("amount") BigDecimal amount) {String xid = context.getXid();log.info("TCC Try阶段 - 冻结资金: xid={}, userId={}, amount={}", xid, userId, amount);try {// 1. 检查账户余额Account account = accountRepository.findByUserId(userId);if (account == null) {throw new AccountException("账户不存在");}if (account.getBalance().compareTo(amount) < 0) {throw new InsufficientBalanceException("余额不足");}// 2. 冻结资金AccountFreeze freeze = new AccountFreeze();freeze.setXid(xid);freeze.setUserId(userId);freeze.setAmount(amount);freeze.setStatus(FreezeStatus.TRYING);freeze.setCreateTime(LocalDateTime.now());freezeRepository.save(freeze);// 3. 扣减可用余额account.setBalance(account.getBalance().subtract(amount));account.setFrozenAmount(account.getFrozenAmount().add(amount));accountRepository.save(account);log.info("资金冻结成功: xid={}, userId={}, amount={}", xid, userId, amount);return true;} catch (Exception e) {log.error("资金冻结失败: xid={}, userId={}, amount={}", xid, userId, amount, e);return false;}}/*** Confirm阶段 - 确认扣款*/public boolean confirmDeduct(BusinessActionContext context) {String xid = context.getXid();Long userId = (Long) context.getActionContext("userId");BigDecimal amount = (BigDecimal) context.getActionContext("amount");log.info("TCC Confirm阶段 - 确认扣款: xid={}, userId={}, amount={}", xid, userId, amount);try {// 1. 查找冻结记录AccountFreeze freeze = freezeRepository.findByXid(xid);if (freeze == null) {log.warn("冻结记录不存在: xid={}", xid);return true; // 幂等性处理}if (freeze.getStatus() == FreezeStatus.CONFIRMED) {log.warn("重复确认: xid={}", xid);return true; // 幂等性处理}// 2. 确认扣款freeze.setStatus(FreezeStatus.CONFIRMED);freeze.setUpdateTime(LocalDateTime.now());freezeRepository.save(freeze);// 3. 减少冻结金额Account account = accountRepository.findByUserId(userId);account.setFrozenAmount(account.getFrozenAmount().subtract(amount));accountRepository.save(account);log.info("扣款确认完成: xid={}, userId={}, amount={}", xid, userId, amount);return true;} catch (Exception e) {log.error("扣款确认失败: xid={}, userId={}, amount={}", xid, userId, amount, e);return false;}}/*** Cancel阶段 - 取消扣款*/public boolean cancelDeduct(BusinessActionContext context) {String xid = context.getXid();Long userId = (Long) context.getActionContext("userId");BigDecimal amount = (BigDecimal) context.getActionContext("amount");log.info("TCC Cancel阶段 - 取消扣款: xid={}, userId={}, amount={}", xid, userId, amount);try {// 1. 查找冻结记录AccountFreeze freeze = freezeRepository.findByXid(xid);if (freeze == null) {log.warn("冻结记录不存在: xid={}", xid);return true; // 幂等性处理}if (freeze.getStatus() == FreezeStatus.CANCELLED) {log.warn("重复取消: xid={}", xid);return true; // 幂等性处理}// 2. 取消冻结freeze.setStatus(FreezeStatus.CANCELLED);freeze.setUpdateTime(LocalDateTime.now());freezeRepository.save(freeze);// 3. 恢复资金Account account = accountRepository.findByUserId(userId);account.setBalance(account.getBalance().add(amount));account.setFrozenAmount(account.getFrozenAmount().subtract(amount));accountRepository.save(account);log.info("扣款取消完成: xid={}, userId={}, amount={}", xid, userId, amount);return true;} catch (Exception e) {log.error("扣款取消失败: xid={}, userId={}, amount={}", xid, userId, amount, e);return false;}}
}/*** Saga模式 - 状态机编排*/
@Component
@Slf4j
public class OrderSagaService {@Autowiredprivate StateMachineEngine stateMachineEngine;/*** 执行订单处理Saga*/public void processOrderSaga(CreateOrderRequest request) {log.info("开始执行订单Saga: userId={}", request.getUserId());try {// 创建状态机实例StateMachineInstance instance = stateMachineEngine.startAsync("orderProcessSaga",UUID.randomUUID().toString(),createSagaContext(request));log.info("订单Saga启动成功: instanceId={}", instance.getId());} catch (Exception e) {log.error("订单Saga启动失败: userId={}", request.getUserId(), e);throw new SagaException("Saga执行失败: " + e.getMessage(), e);}}private Map<String, Object> createSagaContext(CreateOrderRequest request) {Map<String, Object> context = new HashMap<>();context.put("userId", request.getUserId());context.put("productId", request.getProductId());context.put("quantity", request.getQuantity());context.put("amount", request.getAmount());context.put("orderId", null); // 将在状态流转中设置return context;}/*** Saga状态定义*/@SagaOrchestrationStartpublic void startOrderProcess(SagaTransactionContext context) {log.info("Saga开始 - 订单处理: userId={}", context.getVariable("userId"));}@SagaOrchestrationTask("createOrder")public void createOrder(SagaTransactionContext context) {log.info("Saga步骤1 - 创建订单");// 创建订单逻辑Order order = orderService.createOrderLocal((Long) context.getVariable("userId"),(Long) context.getVariable("productId"),(Integer) context.getVariable("quantity"),(BigDecimal) context.getVariable("amount"));context.setVariable("orderId", order.getId());log.info("订单创建成功: orderId={}", order.getId());}@SagaOrchestrationTask("deductBalance")public void deductBalance(SagaTransactionContext context) {log.info("Saga步骤2 - 扣减余额");accountService.deductBalanceLocal((Long) context.getVariable("userId"),(BigDecimal) context.getVariable("amount"));log.info("余额扣减成功");}@SagaOrchestrationTask("reduceStock")public void reduceStock(SagaTransactionContext context) {log.info("Saga步骤3 - 扣减库存");productService.reduceStockLocal((Long) context.getVariable("productId"),(Integer) context.getVariable("quantity"));log.info("库存扣减成功");}@SagaOrchestrationTask("updateOrderStatus")public void updateOrderStatus(SagaTransactionContext context) {log.info("Saga步骤4 - 更新订单状态");orderService.updateOrderStatusLocal((Long) context.getVariable("orderId"),OrderStatus.SUCCESS);log.info("订单状态更新成功");}// 补偿方法@SagaOrchestrationCompensation("createOrder")public void compensateCreateOrder(SagaTransactionContext context) {log.info("Saga补偿 - 取消订单");Long orderId = (Long) context.getVariable("orderId");if (orderId != null) {orderService.cancelOrderLocal(orderId);log.info("订单取消完成: orderId={}", orderId);}}@SagaOrchestrationCompensation("deductBalance")public void compensateDeductBalance(SagaTransactionContext context) {log.info("Saga补偿 - 恢复余额");accountService.refundBalanceLocal((Long) context.getVariable("userId"),(BigDecimal) context.getVariable("amount"));log.info("余额恢复完成");}@SagaOrchestrationCompensation("reduceStock")public void compensateReduceStock(SagaTransactionContext context) {log.info("Saga补偿 - 恢复库存");productService.restoreStockLocal((Long) context.getVariable("productId"),(Integer) context.getVariable("quantity"));log.info("库存恢复完成");}
}

🎯 面试重点总结

💡 分布式事务架构师面试题

1. 事务模式选择

Q: 什么场景选择TCC?什么场景选择Saga?
A:

  • TCC适用场景:资金交易、库存扣减等需要强一致性的核心业务
  • Saga适用场景:订单流程、批处理等长事务业务流程
  • 选择依据:一致性要求、业务复杂度、性能要求
2. 分布式事务设计

Q: 如何设计一个高可用的分布式事务系统?
A:

  • 幂等性设计:防重试、防重复提交
  • 补偿机制:业务补偿、技术补偿
  • 监控告警:事务状态监控、异常告警
  • 容错处理:超时重试、人工介入
3. 性能优化

Q: 分布式事务性能优化策略?
A:

  • 异步处理:非关键步骤异步执行
  • 批量操作:减少网络开销
  • 缓存优化:减少数据库访问
  • 分片策略:避免热点数据

🎖️ 分布式事务架构师核心能力

  1. 方案选型能力:根据业务特点选择合适的事务模式
  2. 系统设计能力:设计高可用、高性能的事务系统
  3. 问题诊断能力:快速定位和解决分布式事务问题
  4. 优化调优能力:持续优化事务系统性能

🔄 分布式事务是分布式系统的核心挑战!掌握技术选型与实现原理,构建高可靠的分布式事务系统!


📌 行动指南

  1. 点赞 → 让更多Java开发者掌握分布式技术
  2. 评论 → 留言"分布式技术"领取[分布式系统设计模板]
  3. 关注 → 追踪更新《更多Java技术精彩内容》(已写完待发布)
  4. 赞赏 → 解锁完整源码+专属技术咨询

🚀 下期预告
《更多Java技术精彩内容》关注可抢先看

📚 相关推荐

  • 漫画Java基础
  • 漫画Spring全家桶
  • 漫画JVM调优

让我们一起在Java的世界里探索更多精彩内容! 🚀

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

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

相关文章

液冷智算数据中心崛起,AI算力联动PC Farm与云智算开拓新蓝海(二)

从算法革新到基础设施升级&#xff0c;从行业渗透到地域布局&#xff0c;人工智能算力正以 “规模扩张 效率提升”双轮驱动中国数字经济转型。中国智能算力规模将在 2025 年突破 1000 EFLOPS&#xff0c;2028 年达到 2781.9 EFLOPS&#xff0c;五年复合增长率 46.2%&#xff0…

《QtPy:Python与Qt的完美桥梁》

QtPy 是什么 在 Python 的广袤编程宇宙中&#xff0c;当涉及到图形用户界面&#xff08;GUI&#xff09;开发&#xff0c;Qt 框架宛如一颗璀璨的明星&#xff0c;散发着独特的魅力。而 QtPy&#xff0c;作为 Python 与 Qt 生态系统交互中的关键角色&#xff0c;更是为开发者们开…

ubuntu环境下调试 RT-Thread

调试 RT-Thread 下载源码 github 搜索 RT-Thread 下载源码 安装 python scons 环境 你已经安装了 kconfiglib&#xff0c;但 scons --menuconfig 仍然提示找不到它。这种情况通常是由于 Python 环境不一致 导致的&#xff1a;你在一个 Python 环境中安装了 kconfiglib&#xff…

【数据结构初阶】--顺序表(二)

&#x1f525;个人主页&#xff1a;草莓熊Lotso &#x1f3ac;作者简介&#xff1a;C研发方向学习者 &#x1f4d6;个人专栏&#xff1a; 《C语言》 《数据结构与算法》《C语言刷题集》《Leetcode刷题指南》 ⭐️人生格言&#xff1a;生活是默默的坚持&#xff0c;毅力是永久的…

Java中的方法传参机制

1. 概述Java中的方法传参机制分为两种&#xff1a;值传递&#xff08;Pass by Value&#xff09; 和 引用传递&#xff08;Pass by Reference&#xff09;。然而&#xff0c;Java中所有的参数传递都是值传递&#xff0c;只不过对于对象来说&#xff0c;传递的是对象的引用地址的…

C++——this关键字和new关键字

一、this 关键字1. 什么是 this&#xff1f;this 是 C 中的一个隐式指针&#xff0c;它指向当前对象&#xff08;即调用成员函数的对象&#xff09;&#xff0c;在成员函数内部使用&#xff0c;用于引用调用该函数的对象。每个类的非静态成员函数内部都可以使用 this。使用 thi…

Python中类静态方法:@classmethod/@staticmethod详解和实战示例

在 Python 中&#xff0c;类方法 (classmethod) 和静态方法 (staticmethod) 是类作用域下的两种特殊方法。它们使用装饰器定义&#xff0c;并且与实例方法 (def func(self)) 的行为有所不同。1. 三种方法的对比概览方法类型是否访问实例 (self)是否访问类 (cls)典型用途实例方法…

FastGPT革命:下一代语言模型的极速进化

本文深度解析FastGPT核心技术架构&#xff0c;涵盖分布式推理、量化压缩、硬件加速等前沿方案&#xff0c;包含完整落地实践指南&#xff0c;助你掌握大模型高效部署的终极武器。引言&#xff1a;当大模型遭遇速度瓶颈2023年&#xff0c;ChatGPT引爆全球AI热潮&#xff0c;但企…

Geant4 安装---Ubuntu

安装工具 C/C工具包 sudo apt install build-essentialCmake sudo apt install -y cmakeccmake sudo apt install -y cmake-curses-gui安装Qt可视化工具(不需要可视化可以不安装) sudo apt-get install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools qtcreator 安装Ope…

Spring Boot中请求参数读取方式

目录 一、前言 二、六种参数读取方式 1.RequestParam 2.PathVariable 3.RequestBody 4.RequestHeader 5.CookieValue 6.MatrixVariable 三、对比和搭配 1.适用方法类型及建议使用场景 2.建议使用的请求路径注解 3. 多种参数同时使用 4.同一请求不同方案&#xff1f…

2025华为OD机试真题最新题库 (B+C+D+E+2025A+2025B卷) + 在线OJ在线刷题使用(C++、Java、Python C语言 JS合集)(正在更新2025B卷,目前已收录710道)

2025年&#xff0c;已经开始使用AB卷题库&#xff0c;题目和往期一样&#xff0c;旧题加新题的组合&#xff0c;有题目第一时间更新&#xff0c;大家可以跟着继续学习&#xff0c;目前使用复用题较多&#xff0c;可在OJ上直接找到对应的AB卷学习&#xff0c;可以放心学习&#…

分析新旧因子相关性

计算一组新因子、并分析它们与已有因子间的相关性1. 导入库和初始化环境功能代码解析数据加载2. 定义新因子计算函数功能代码解析因子 1&#xff1a;波动率过滤器&#xff08;filter_001_1&#xff09;因子 2&#xff1a;ATR 过滤器&#xff08;filter_001_2&#xff09;因子 3…

Unity Demo——3D平台跳跃游戏笔记

今天是一个3D平台跳跃游戏的笔记。我们按照以下分类来对这个项目的代码进行学习&#xff1a;核心游戏系统 (Core Game Systems)核心游戏系统是IkunOdyssey项目的基础&#xff0c;负责所有游戏对象&#xff08;如玩家、敌人、道具等&#xff09;的通用行为和物理交互。它通过实体…

【C语言】回调函数、转移表、qsort 使用与基于qsort改造冒泡排序

文章目录数组指针/指针数组函数指针函数指针数组函数指针数组用途(转移表)回调函数qsort函数基于qsort改造冒泡排序源码数组指针/指针数组 int arr1[5] { 1,2,3,4,5 };int (*p1)[5] &arr1; //p1是数组指针变量int* arr2[5] { 0 }; //arr2是指针数组指针数组是存放指…

vue3 uniapp 使用ref更新值后子组件没有更新 ref reactive的区别?使用from from -item执行表单验证一直提示没有值

遇到这样一个问题&#xff0c;我有个1个页面A&#xff0c;一个from表单组件&#xff0c;一个form-item组件&#xff0c; 使用是这样的&#xff0c;我在父组件A中使用 &#xff0c;执行表单验证一直提示没有值咱们先来讲一讲ref 和reactive的区别 ref 用来创建一个基本类型或单…

PyQt5布局管理(QBoxLayout(框布局))

QBoxLayout&#xff08;框布局&#xff09; 采用QBoxLayout类可以在水平和垂直方向上排列控件&#xff0c;QHBoxLayout和 QVBoxLayout类继承自QBoxLayout类。 QHBoxLayout&#xff08;水平布局&#xff09; 采用QHBoxLayout类&#xff0c;按照从左到右的顺序来添加控件。QHBoxL…

Grok 4作战图刷爆全网,80%华人横扫硅谷!清华上交校友领衔,95后站C位

来源 | 新智元短短两年&#xff0c;马斯克Grok 4的横空出世&#xff0c;让xAI团队一举站上AI之巅。昨日一小时发布会&#xff0c;Grok 4让所有人大开眼界&#xff0c;直接刷爆了AIME 2025、人类最后的考试&#xff08;HLE&#xff09;两大基准。这是狂堆20万GPU才换来的惊人成果…

AI大模型(七)Langchain核心模块与实战(二)

Langchain核心模块与实战&#xff08;二&#xff09;Langchian向量数据库检索Langchian构建向量数据库和检索器批量搜索返回与之相似度最高的第一个检索器和模型结合得到非笼统的答案LangChain构建代理通过代理去调用Langchain构建RAG的对话应用包含历史记录的对话生成Langchia…

Flutter基础(前端教程①-容器和控件位置)

一个红色背景的 Container垂直排列的 Column 布局中央的 ElevatedButton按钮下方的白色文本import package:flutter/material.dart;void main() {runApp(const MyApp()); }class MyApp extends StatelessWidget {const MyApp({Key? key}) : super(key: key);overrideWidget bu…

CSS flex

目录 flex-box和flex-item 主轴和副轴 ​编辑 flex-box的属性 flex-direction flex-wrap flex-flow justify-content ​编辑​align-items align-content flex-item的属性 flex-basis flex-grow flex-shrink flex flex-box和flex-item 当把一个块级元素的displ…