Java-08 深入浅出 MyBatis - 多对多模型 SqlMapConfig 与 Mapper 详细讲解测试
点一下关注吧!!!非常感谢!!持续更新!!!
大数据篇正在更新!https://blog.csdn.net/w776341482/category_12713819.html
目前已经更新到了:
- MyBatis(正在更新)
多对多
在数据库设计中,“多对多”关系是指两张表中的记录可以互相关联,多条记录可以关联多条记录。例如,“学生”表和“课程”表之间的关系可能是多对多,因为一个学生可以选修多门课程,而一门课程也可能被多名学生选修。
要实现多对多的关系,通常需要使用一个 中间表(关联表)。这个中间表起到桥梁的作用,将两个表的记录通过其主键关联起来。
多对多关系的特点
- 双向性:A可以关联多个B,同时B也可以关联多个A。
- 需要中间表:为了表示这种关系,通常使用一个中间表来维护关联。
- 灵活性高:多对多关系非常适合用来表示复杂的业务逻辑,尤其是在需要动态添加或修改关系时。
多对多关系的扩展
添加额外字段
中间表可以扩展为更多功能。例如,可以为选课添加时间戳、成绩字段、是否通过等。
索引优化
为中间表中的外键添加索引,提高查询性能。
ORM 框架支持
现代框架(如 Hibernate、Django ORM)支持多对多关系的自动管理。在代码中只需要声明模型的关系,底层会自动生成并管理中间表。
查询模型
用户表和角色的关系,一个用户有多个角色,一个角色被多个用户使用。
多对多的查询的需求,查询用户同时查询出该用户所有的角色。
创建表
wzk_user_role
CREATE TABLE `wzk_user_role` (`id` int(11) NOT NULL,`user_id` int(11) NOT NULL,`role_id` int(11) NOT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
wzk_role
CREATE TABLE `wzk_role` (`id` int(11) NOT NULL,`rolename` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
插入数据
wzk_user_role
INSERT INTO wzk_user_role
VALUES(1, 1, 1);INSERT INTO wzk_user_role
VALUES(1, 2, 2);
wzk_role
INSERT INTO wzk_role
VALUES(1, "ADMIN");INSERT INTO wzk_role
VALUES(2, "USER");
查询语句
select u.*,r.*,r.id rid from wzk_user u
left join wzk_user_role ur on u.id=ur.user_id
inner join wzk_role r on ur.role_id=r.id;
执行结果如下所示:
创建类
WzkUser
这里需要加入新的字段
package icu.wzk.model;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.util.Date;
import java.util.List;@Data
@AllArgsConstructor
@NoArgsConstructor
public class WzkUser {private int id;private String username;private String password;private Date birthday;private List<WzkOrder> orderList;private List<WzkRole> roleList;
}
对应的截图如下所示:
WzkRole
package icu.wzk.model;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor
public class WzkRole {private Integer id;private String rolename;
}
对应的截图如下所示:
UserMapper
package icu.wzk.mapper;import icu.wzk.model.WzkUser;import java.util.List;public interface UserMapper {List<WzkUser> findAll();List<WzkUser> findAllUserAndRole();
}
对应的截图如下所示:
UserMapper.xml
<resultMap id="userRoleMap" type="icu.wzk.model.WzkUser"><result column="id" property="id"></result><result column="username" property="username"></result><result column="password" property="password"></result><result column="birthday" property="birthday"></result><collection property="roleList" ofType="icu.wzk.model.WzkRole"><result column="rid" property="id"></result><result column="rolename" property="rolename"></result></collection>
</resultMap><select id="findAllUserAndRole" resultMap="userRoleMap">SELECT u.*, r.*, r.id ridFROM wzk_user uLEFT JOIN wzk_user_role ur on u.id=ur.user_idINNER JOIN wzk_role r on ur.role_id=r.id;
</select>
对应的截图如下所示:
编写代码
package icu.wzk;import icu.wzk.mapper.UserMapper;
import icu.wzk.model.WzkUser;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;
import java.io.InputStream;
import java.util.List;public class WzkIcu10 {public static void main(String[] args) throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper userMapper = sqlSession.getMapper(UserMapper.class);List<WzkUser> dataList = userMapper.findAllUserAndRole();dataList.forEach(System.out::println);sqlSession.close();}
}
代码的截图如下所示:
运行结果
运行上面的代码,控制台输出的结果如下所示:
WzkUser(id=1, username=wzk, password=icu, birthday=Mon Nov 11 00:00:00 CST 2024, orderList=null, roleList=[WzkRole(id=1, rolename=ADMIN)])
WzkUser(id=2, username=wzk2, password=icu2, birthday=Mon Nov 11 00:00:00 CST 2024, orderList=null, roleList=[WzkRole(id=2, rolename=USER)])
24/11/12 18:02:33 DEBUG jdbc.JdbcTransaction: Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@15b204a1]
对应的截图如下所示:
注意事项
- 索引优化:为中间表的外键字段创建索引,提升查询性能。
- 关系约束:使用外键约束维护数据一致性,避免孤立数据。
- 批量操作:在大规模插入、更新时,尽量使用批量操作,提升效率。
- 软删除:中间表可以设计“软删除”标志位,用于保留历史记录。
大表的分表与分库
问题背景
在超大规模应用中,单表可能变得过于庞大,导致性能问题。
解决方法
- 垂直分表:将额外字段分离,减少单表宽度。
- 水平分表:将记录按学生或课程拆分到多个表。
- 分库:将不同表分布在多个数据库实例上。
日志和监控
问题背景
多对多关系中的数据修改频繁,容易引入错误,例如重复记录、孤立记录等。
解决方法
- 日志记录:记录每次数据操作的详细信息。
- 监控工具:定期检查中间表是否存在孤立记录或重复记录。
暂时小结
优化多对多关系模型需要从多个方面入手:
- 提升性能:通过索引、分区、批量操作等方式优化查询和更新。
- 保证数据一致性:通过外键约束和事务处理避免数据异常。
- 提高灵活性:通过软删除和日志记录保留历史数据,支持恢复和审计。
- 应对大数据场景:通过分区、分表或分库设计,确保系统扩展性。
相关文章:
Java-08 深入浅出 MyBatis - 多对多模型 SqlMapConfig 与 Mapper 详细讲解测试
点一下关注吧!!!非常感谢!!持续更新!!! 大数据篇正在更新!https://blog.csdn.net/w776341482/category_12713819.html 目前已经更新到了: MyBatisÿ…...
单元测试、集成测试、系统测试、验收测试、压力测试、性能测试、安全性测试、兼容性测试、回归测试(超详细的分类介绍及教学)
目录 1.单元测试 实现单元测试的方法: 注意事项: 2.集成测试 需注意事项: 实现集成测试的方法: 如何实现高效且可靠的集成测试: 3.系统测试 实现系统测试的方法: 须知注意事项: 4.验收测试 实现验…...
整车安全需求考量的多维度深度剖析
在汽车工程领域,整车安全需求的确定是一项复杂且系统的工程,其涵盖了多个关键维度的综合考量。从需求的萌生到最终的落地实施,每一个环节都紧密相扣,涉及众多技术细节与实际操作的权衡。 一、需求来源的多渠道挖掘 整车安全需求的来源广泛,其中 TARA(威胁分析与风险评估)…...
虚幻引擎---初识篇
一、学习途径 虚幻引擎官方文档:https://dev.epicgames.com/documentation/zh-cn/unreal-engine/unreal-engine-5-5-documentation虚幻引擎在线学习平台:https://dev.epicgames.com/community/unreal-engine/learning哔哩哔哩:https://www.b…...
Oracle - 多区间按权重取值逻辑 ,分时区-多层级-取配置方案(二)
Oracle - 多区间按权重取值逻辑 ,分时区-多层级-取配置方案https://blog.csdn.net/shijianduan1/article/details/133386281 某业务配置表,按配置的时间区间及组织层级取方案,形成报表展示出所有部门方案的取值; 例如࿰…...
线性代数的发展简史
线性代数的发展简史 线性代数作为数学的一个重要分支,其发展历史悠久而丰富。从古代文明中的基础计算到现代复杂的理论体系,线性代数经历了多个阶段的演变。 古代的起源 线性代数的雏形可以追溯到古埃及、古希腊、古印度和古代中国时期。这些早期文明…...
git使用详解
一、git介绍 1、git简介 Git 是一个开源的分布式版本控制系统(最先进的,没有之一),用于敏捷高效地处理任何或小或大的项目。 Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。 Git 与常用…...
ros2学习日记_241124_ros相关链接
前言 提醒: 文章内容为方便作者自己后日复习与查阅而进行的书写与发布,其中引用内容都会使用链接表明出处(如有侵权问题,请及时联系)。 其中内容多为一次书写,缺少检查与订正,如有问题或其他拓展…...
【SQL】【数据库】语句翻译例题
SQL自然语言到SQL翻译知识点 以下是将自然语言转化为SQL语句的所有相关知识点,分门别类详细列出,并结合技巧说明。 1. 数据库操作 创建数据库 自然语言:创建一个名为“TestDB”的数据库。 CREATE DATABASE TestDB;技巧:识别**“创…...
图书管理系统(源码+数据库+报告)
基于SpringBoot的图书管理系统,系统包含两种角色:管理员、用户,系统分为前台和后台两大模块,主要功能如下。 前台: - 首页:展示系统推荐、热门图书等信息。 - 论坛:提供用户交流讨论的平台。 - 公告信息&a…...
python中lxml 库之 etree 使用详解
目录 一、 etree 介绍二、xpath 解析 html/xml1、第一步就是使用 etree 连接 html/xml 代码/文件。2、 xpath 表达式定位① xpath结合属性定位② xpath文本定位及获取③ xpath层级定位④ xpath索引定位⑤ xpath模糊匹配 一、 etree 介绍 lxml 库是 Python 中一个强大的 XML 处…...
vue3(十九)-基础入门之vue-nuxt反向代理
一、反向代理 1、下载 nuxtjs/proxy 使用 npm npm install nuxtjs/proxy 或使用 yarn yarn add nuxtjs/proxy 2、配置 nuxt.config.js 文件 export default {modules: [nuxtjs/axios,nuxtjs/proxy],axios: {baseURL: /,proxy: true},proxy: {/api/: {target: https://i.maoya…...
Unity3D 截图
使用 Unity3D 自带的截图接口,制作截图工具。 截图 有时候我们想对 Unity 的窗口进行截图,如果直接使用一些截图工具,很难截取到一张完整分辨率的图片(例如,我们想要截取一张 1920 * 1080 的图片)。 其实…...
【机器学习】近似分布的熵到底是p(x)lnq(x)还是q(x)lnq(x)?
【1】通信的定义 信息量(Information Content)是信息论中的一个核心概念,用于定量描述一个事件发生时所提供的“信息”的多少。它通常用随机变量 𝑥的概率分布来定义。事件 𝑥发生所携带的信息量由公式给出࿱…...
C语言:深入理解指针
一.内存和地址 我们知道计算机上CPU(中央处理器)在处理数据的时候,需要的数据是在内存中读取的,处理后的数据也会放回内存中,那我们买电脑的时候,电脑上内存是 8GB/16GB/32GB 等,那这些内存空间…...
Vue实训---4-使用Pinia实现menu菜单展示/隐藏
0.menu菜单展示/隐藏实现方法 Menu 菜单 | Element Plus中,当:collapse"isCollapse"其中isCollapse的值为true时菜单栏隐藏,当isCollapse的值为false时菜单栏显示。接下来使用pinia实现CommonAside.vue和CommonHeader.vue组件之间数据的共享&…...
Fakelocation Server服务器/专业版 Centos7
前言:需要Centos7系统 Fakelocation开源文件系统需求 Centos7 | Fakelocation | 任务一 更新Centos7 (安装下载不再赘述) sudo yum makecache fastsudo yum update -ysudo yum install -y kernelsudo reboot//如果遇到错误提示为 Another app is curre…...
网络安全,文明上网(4)掌握网络安全技术
前言 在数字化时代,个人信息和企业数据的安全变得尤为重要。为了有效保护这些宝贵资产,掌握一系列网络安全技术是关键。 核心技术及实施方式 1. 网络监控与过滤系统: 这些系统构成了网络防御体系的基石,它们负责监控网络通信&…...
Ettus USRP X410
总线连接器: 以太网 RF频率范围: 1 MHz 至 7.2 GHz GPSDO: 是 输出通道数量: 4 RF收发仪瞬时带宽: 400 MHz 输入通道数量: 4 FPGA: Zynq US RFSoC (ZU28DR) 1 MHz to 7.2 GHz,400 MHz带宽,GPS驯服OCXO,USRP软件无线电设备 Ettus USRP X410集…...
在SQLyog中导入和导出数据库
导入 假如我要导入一个xxx.sql,我就先创建一个叫做xxx的数据库。 然后右键点击导入、执行SQL脚本 选择要导入的数据库文件的位置,点击执行即可 注意: 导入之后记得刷新一下导出 选择你要导出的数据库 右键选择:备份/导出、…...
一文了解Spring提供的几种扩展能力
基于 spring bean 的扩展 1. BeanPostProcessor spring 提供的针对 bean 的初始化过程时提供的扩展能力,从方法名也很容易看出,提供的两个方法分别是为 bean 对象提供了初始化之前以及初始化之后的扩展能力。 package com.wyl.conf;import org.spring…...
VXLAN说明
1. 什么是 VXLAN ? VXLAN(Virtual Extensible LAN,虚拟扩展局域网)是一种网络虚拟化技术,旨在通过在现有的物理网络上实现虚拟网络扩展,从而克服传统 VLAN 的一些限制。 VXLAN 主要用于数据中心、云计算环…...
MyBatis基本使用
一、向SQL语句传参: 1.MyBatis日志输出配置: mybatis配置文件设计标签和顶层结构如下: 可以在mybatis的配置文件使用settings标签设置,输出运过程SQL日志,通过查看日志,可以判定#{}和${}的输出效果 settings设置项: logImpl指定 MyBatis 所用日志的具…...
Linux笔记---进程:进程切换与O(1)调度算法
1. 补充概念 1.1 并行与并发 竞争性:系统进程数目众多,而CPU资源只有少量,甚至只有1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级。独立性:多进程运…...
Flink学习连载第二篇-使用flink编写WordCount(多种情况演示)
使用Flink编写代码,步骤非常固定,大概分为以下几步,只要牢牢抓住步骤,基本轻松拿下: 1. env-准备环境 2. source-加载数据 3. transformation-数据处理转换 4. sink-数据输出 5. execute-执行 DataStream API开发 //n…...
[AutoSar]BSW_Diagnostic_007 BootLoader 跳转及APP OR boot response 实现
目录 关键词平台说明背景一、Process Jump to Bootloader二、相关函数和配置2.1 Dcm_GetProgConditions()2.2 Dcm_SetProgConditions() 三、如何实现在APP 还是BOOT 中对10 02服务响应3.1 配置3.2 code 四、报文五、小结 关键词 嵌入式、C语言、autosar、OS、BSW、UDS、diagno…...
用 Python 写了一个天天酷跑(附源码)
Hello,大家好,给大家说一下,我要开始装逼了 这期写个天天酷跑玩一下叭! 制作一个完整的“天天酷跑”游戏涉及很多方面,包括图形渲染、物理引擎、用户输入处理、游戏逻辑等。由于Python是一种高级编程语言,…...
WebGL进阶(九)光线
理论基础: 点光源 符合向量定义,末减初。 平行光 环境光 效果: 点光源 平行光 环境光 源码: 点光源 // 顶点着色器程序let vertexstring attribute vec4 a_position; // 顶点位置属性uniform mat4 u_formMatrix; // 用于变换…...
Lucene(2):Springboot整合全文检索引擎TermInSetQuery应用实例附源码
前言 本章代码已分享至Gitee: https://gitee.com/lengcz/springbootlucene01 接上文。Lucene(1):Springboot整合全文检索引擎Lucene常规入门附源码 如何在指定范围内查询。从lucene 7 开始,filter 被弃用,导致无法进行调节过滤。 TermInSetQuery 指定…...
HarmonyOS(57) UI性能优化
性能优化是APP开发绕不过的话题,那么在HarmonyOS开发过程中怎么进行性能优化呢?今天就来总结下相关知识点。 UI性能优化 1、避免在组件的生命周期内执行高耗时操作2、合理使用ResourceManager3、优先使用Builder方法代替自定义组件4、参考资料 1、避免在…...
机器学习周志华学习笔记-第5章<神经网络>
机器学习周志华学习笔记-第5章<神经网络> 卷王,请看目录 5模型的评估与选择5.1 神经元模型5.2 感知机与多层网络5.3 BP(误逆差)神经网络算法 5.4常见的神经网络5.4.1 RBF网络(Radial Basis Function Network,径向基函数网络࿰…...
SQL进阶技巧:如何进行数字范围统计?| 货场剩余货位的统计查询方法
目录 0 场景描述 1 剩余空位区间和剩余空位编号统计分析 2 查找已用货位区间 3 小结 0 场景描述 这是在做一个大型货场租赁系统时遇到的问题,在计算货场剩余存储空间时,不仅仅需要知道哪些货位是空闲的,还要能够判断出哪些货位之间是连续的。因为在新货物入场时,可…...
Xilinx IP核(3)XADC IP核
文章目录 1. XADC介绍2.输入要求3.输出4.XADC IP核使用5.传送门 1. XADC介绍 xadc在 所有的7系列器件上都有支持,通过将高质量模拟模块与可编程逻辑的灵活性相结合,可以为各种应用打造定制的模拟接口,XADC 包括双 12 位、每秒 1 兆样本 (MSP…...
现代大数据架构设计与实践:从数据存储到处理的全面解读
1. 引言 随着信息技术的不断发展,数据已经成为企业和组织最宝贵的资产之一。大数据的应用已经渗透到各个行业,无论是电商、金融,还是医疗、物流,如何有效管理、存储和处理海量的数据已经成为企业成功的关键之一。本文将深入探讨现代大数据架构的设计理念与技术实践,从数据…...
详细教程-Linux上安装单机版的Hadoop
1、上传Hadoop安装包至linux并解压 tar -zxvf hadoop-2.6.0-cdh5.15.2.tar.gz 安装包: 链接:https://pan.baidu.com/s/1u59OLTJctKmm9YVWr_F-Cg 提取码:0pfj 2、配置免密码登录 生成秘钥: ssh-keygen -t rsa -P 将秘钥写入认…...
前端项目支持tailwindcss写样式
安装 npm install -D tailwindcss npx tailwindcss init配置 tailwind.config.js //根据个人需求填写,比如vue简单配置 /** type {import(tailwindcss).Config} */ module.exports {darkMode: "class",corePlugins: {preflight: false},content: [&quo…...
工程师 - 智能家居方案介绍
1. 智能家居硬件方案概述 智能家居硬件方案是实现家庭自动化的重要组件,通过集成各种设备来提升生活的便利性、安全性和效率。这些方案通常结合了物联网技术,为用户提供智能化、自动化的生活体验。硬件方案的选择直接影响到智能家居系统的性能、兼容性、…...
H.264/H.265播放器EasyPlayer.js网页全终端安防视频流媒体播放器关于iOS不能系统全屏
在数字化时代,流媒体播放器已成为信息传播和娱乐消遣的主流载体。随着技术的进步,流媒体播放器的核心技术和发展趋势不断演变,影响着整个行业的发展方向。 EasyPlayer播放器属于一款高效、精炼、稳定且免费的流媒体播放器,可支持…...
2.langchain中的prompt模板 (FewShotPromptTemplate)
本教程将介绍如何使用 LangChain 库中的 PromptTemplate 和 FewShotPromptTemplate 来构建和运行提示(prompt),并通过示例数据展示其应用。 安装依赖 首先,确保你已经安装了 langchain 和相关依赖: pip install lan…...
TCP/IP
1、浏览器输入网址后发生了什么 1)应用层:浏览器解析ULR,生成发送给web服务器的请求信息,HTTP请求报文生成,委托给操作系统将消息发送给web服务器,发送之前需要查询服务器域名对应的IP地址(需要…...
详细探索xinput1_3.dll:功能、问题与xinput1_3.dll丢失的解决方案
本文旨在深入探讨xinput1_3.dll这一动态链接库文件。首先介绍其在计算机系统中的功能和作用,特别是在游戏和输入设备交互方面的重要性。然后分析在使用过程中可能出现的诸如文件丢失、版本不兼容等问题,并提出相应的解决方案,包括重新安装相关…...
Spring:AOP切入点表达式
对于AOP中切入点表达式,我们总共会学习三个内容,分别是语法格式、通配符和书写技巧。 语法格式 首先我们先要明确两个概念: 切入点:要进行增强的方法切入点表达式:要进行增强的方法的描述方式 对于切入点的描述,我们其实是有两中方式的&a…...
STM32的中断(什么是外部中断和其他中断以及中断号是什么)
一、什么是EXTI 和NVIC EXTI(External Interrupt/Event Controller)EXTI 是外部中断/事件控制器,它负责处理外部信号变化,并将信号传递给中断控制器(如 NVIC)。主要负责以下功能: 外部事件检测…...
MySQL底层概述—1.InnoDB内存结构
大纲 1.InnoDB引擎架构 2.Buffer Pool 3.Page管理机制之Page页分类 4.Page管理机制之Page页管理 5.Change Buffer 6.Log Buffer 1.InnoDB引擎架构 (1)InnoDB引擎架构图 (2)InnoDB内存结构 (1)InnoDB引擎架构图 下面是InnoDB引擎架构图,主要分为内存结构和磁…...
Linux 下进程基本概念与状态
文章目录 一、进程的定义二、 描述进程-PCBtask_ struct内容分类 三、 进程状态 一、进程的定义 狭义定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed)。广义定义:进程是一个具有一定…...
Go语言链接Redis数据库
1.使用go get命令安装go-redis/v8库: 我这里使用的vscode工具安装: go get github.com/go-redis/redis/v82.创建Redis客户端实例 使用以下Go代码连接到Redis服务器并执行命令: package mainimport ("context""fmt"&q…...
SQL 分页查询详解
在处理大型数据集时,分页查询是一种常见的技术,用于将数据分成多个小块,以便逐步加载和显示。这不仅可以提高应用的性能,还可以提升用户体验,避免一次性加载过多数据导致页面加载缓慢或资源消耗过大。本文将详细介绍 S…...
ACP科普:风险价值矩阵
风险价值矩阵(Risk-Value Matrix)是一种常用的工具,用于在项目管理中帮助团队识别、评估和优先处理风险。它通过将风险和价值两个因素进行结合,帮助决策者明确哪些风险需要优先关注和处理,从而有效地管理项目的不确定性…...
计算机网络socket编程(2)_UDP网络编程实现网络字典
个人主页:C忠实粉丝 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C忠实粉丝 原创 计算机网络socket编程(2)_UDP网络编程实现网络字典 收录于专栏【计算机网络】 本专栏旨在分享学习计算机网络的一点学习笔记,欢迎大家在评论区交流讨…...
(Keil)MDK-ARM各种优化选项详细说明、实际应用及拓展内容
参考 MDK-ARM各种优化选项详细说明、实际应用及拓展内容 本文围绕MDK-ARM优化选项,以及相关拓展知识(微库、实际应用、调试)进行讲述,希望对你今后开发项目有所帮助。 1 总述 我们所指的优化,主要两方面: 1.代码大小(Size) 2.代码性能(运行时间) 在MDK-ARM中,优…...