Mybatis动态之灵活使用

news2025/1/12 19:05:40

 

目录

​编辑

1.MyBatis中的动态SQL是什么?

2.MyBatis中的动态SQL作用

3.代码演示

4. #和 $使用

2.1  #使用

 ( 1 ) #占位符语法

          ( 2 ) #优点#占位符语法在使用动态SQL时具有以下优点:

2.2  $使用

 ( 1 ) $占位符语法

          ( 2 ) $优点$占位符语法在使用动态SQL时具有以下优点:

2.3代码演示

5.resultType及resultMap的区别

5.1区别:

5.2代码演示:

5.3总结:


1.MyBatis中的动态SQL是什么?

MyBatis是一种Java持久化框架,它提供了一种简单且灵活的方式来处理数据库操作。动态SQL是MyBatis中的一个重要特性,它允许开发人员根据不同的条件生成不同的SQL语句。
动态SQL可以在XML映射文件中使用,也可以在注解中使用。它通过使用一些特殊的标签和关键字来实现动态生成SQL语句。这些标签包括if、choose、when、otherwise、trim、where、set等。

2.MyBatis中的动态SQL作用

MyBatis是一个开源的持久层框架,用于将Java对象映射到关系型数据库。动态SQL是MyBatis中的一个重要特性,它允许在SQL语句中根据不同的条件动态地生成不同的SQL片段,从而实现灵活的查询和更新操作。

动态SQL在MyBatis中的作用主要体现在以下几个方面:

1. 条件判断:动态SQL可以根据不同的条件判断来生成不同的SQL语句。例如,在查询操作中,可以根据用户输入的条件动态地拼接WHERE子句,从而实现灵活的查询功能。在更新操作中,可以根据不同的条件判断来决定是否更新某些字段或执行不同的更新操作。

2. 循环迭代:动态SQL还支持循环迭代,可以对集合类型的参数进行遍历,并在SQL语句中生成对应的循环逻辑。这样可以方便地处理批量插入、批量更新等操作。

3. 动态排序:通过动态SQL,可以根据用户指定的排序字段和排序方式来生成ORDER BY子句,从而实现动态排序功能。

4. 动态表名和列名:有时候需要根据不同的场景使用不同的表名或列名,动态SQL可以根据条件来生成对应的表名或列名,从而实现动态的数据库操作。

3.代码演示

根据我们自动生成的xml,接口,实体进行增加代码进行动态SQL的演示操作 自动生成的实体代码( Book )对象  

package com.sy.model;
/**
 * @author 谌艳
 * @site www.shenyan.com
 * @create 2023-08-19 20:49
 */
public class Book {
    private Integer bid;

    private String bname;

    private Float price;

    public Book(Integer bid, String bname, Float price) {
        this.bid = bid;
        this.bname = bname;
        this.price = price;
    }

    public Book() {
        super();
    }

    public Integer getBid() {
        return bid;
    }

    public void setBid(Integer bid) {
        this.bid = bid;
    }

    public String getBname() {
        return bname;
    }

    public void setBname(String bname) {
        this.bname = bname;
    }

    public Float getPrice() {
        return price;
    }

    public void setPrice(Float price) {
        this.price = price;
    }


    @Override
    public String toString() {
        return "Book{" +
                "bid=" + bid +
                ", bname='" + bname + '\'' +
                ", price=" + price +
                '}';
    }
}

自动生成的实体接口 BookMapper

package com.sy.mapper;

import com.sy.model.Book;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface BookMapper {
    int deleteByPrimaryKey(Integer bid);

    int insert(Book record);

    int insertSelective(Book record);

    Book selectByPrimaryKey(Integer bid);

    int updateByPrimaryKeySelective(Book record);

    int updateByPrimaryKey(Book record);

   List<Book> selectByBids(@Param("bids") List bids);

    List<Book> like1(@Param("bname")String bname);
    List<Book> like2(@Param("bname")String bname);
    List<Book> like3(@Param("bname")String bname);
    List<Book> List1();
    List<Book> List2();
}

  自动生成的 BookMapper.xml 配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sy.mapper.BookMapper" >
  <resultMap id="BaseResultMap" type="com.sy.model.Book" >
    <constructor >
      <idArg column="bid" jdbcType="INTEGER" javaType="java.lang.Integer" />
      <arg column="bname" jdbcType="VARCHAR" javaType="java.lang.String" />
      <arg column="price" jdbcType="REAL" javaType="java.lang.Float" />
    </constructor>
  </resultMap>
  <sql id="Base_Column_List" >
    bid, bname, price
  </sql>
  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
    select 
    <include refid="Base_Column_List" />
    from t_mvc_book
    where bid = #{bid,jdbcType=INTEGER}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
    delete from t_mvc_book
    where bid = #{bid,jdbcType=INTEGER}
  </delete>
  <insert id="insert" parameterType="com.sy.model.Book" >
    insert into t_mvc_book (bid, bname, price
      )
    values (#{bid,jdbcType=INTEGER}, #{bname,jdbcType=VARCHAR}, #{price,jdbcType=REAL}
      )
  </insert>
  <insert id="insertSelective" parameterType="com.sy.model.Book" >
    insert into t_mvc_book
    <trim prefix="(" suffix=")" suffixOverrides="," >
      <if test="bid != null" >
        bid,
      </if>
      <if test="bname != null" >
        bname,
      </if>
      <if test="price != null" >
        price,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides="," >
      <if test="bid != null" >
        #{bid,jdbcType=INTEGER},
      </if>
      <if test="bname != null" >
        #{bname,jdbcType=VARCHAR},
      </if>
      <if test="price != null" >
        #{price,jdbcType=REAL},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="com.sy.model.Book" >
    update t_mvc_book
    <set >
      <if test="bname != null" >
        bname = #{bname,jdbcType=VARCHAR},
      </if>
      <if test="price != null" >
        price = #{price,jdbcType=REAL},
      </if>
    </set>
    where bid = #{bid,jdbcType=INTEGER}
  </update>
  <update id="updateByPrimaryKey" parameterType="com.sy.model.Book" >
    update t_mvc_book
    set bname = #{bname,jdbcType=VARCHAR},
      price = #{price,jdbcType=REAL}
    where bid = #{bid,jdbcType=INTEGER}
  </update>

  <select id="selectByBids" resultType="com.sy.model.Book" parameterType="java.lang.String">
    select
    <include refid="Base_Column_List" />
    from  t_mvc_book
    where bid in
    <foreach collection="bids" item="bid" open="(" close=")" separator=",">
      #{bid}
    </foreach>
  </select>

  <select id="like1" resultType="com.sy.model.Book" parameterType="java.lang.String">
    select
    <include refid="Base_Column_List" />
    from  t_mvc_book
    where bname like #{bname}
  </select>

  <select id="like2" resultType="com.sy.model.Book" parameterType="java.lang.String">
    select
    <include refid="Base_Column_List" />
    from  t_mvc_book
    where bname like '${bname}'
  </select>

  <select id="like3" resultType="com.sy.model.Book" parameterType="java.lang.String">
    select
    <include refid="Base_Column_List" />
    from  t_mvc_book
    where bname like concat('%',#{bname}, '%')
  </select>

  <select id="List1" resultType="com.sy.model.Book">
  select
  <include refid="Base_Column_List" />
  from  t_mvc_book
  where bid=#{bid,jdbcType=INTEGER}
</select>

  <select id="List2" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from  t_mvc_book
    where bid=#{bid,jdbcType=INTEGER}
  </select>
</mapper>

 其中的动态SQL可以根据自己的需要进行编写 :

<select id="selectByBids" resultType="com.sy.model.Book" parameterType="java.lang.String">
    select
    <include refid="Base_Column_List" />
    from  t_mvc_book
    where bid in
    <foreach collection="bids" item="bid" open="(" close=")" separator=",">
      #{bid}
    </foreach>
  </select>

再将以下代码增加到增加编写的接口中 

封装方法

 List<Book> selectByBids(@Param("bids") List bids);

 然后在实现类中增加以下代码

方法实现

@Override
    public List<Book> selectByBids(List bids) {
        return bm.selectByBids(bids);
    }

最后我们就可以在Demo1测试类中进行方法调用测试

在Demo1中增加以下代码进行测试 :  

 @Test
    public void testByid(){
        List<Integer> bids = Arrays.asList(new Integer[]{33, 36, 37});
        bookBiz.selectByBids(bids).forEach(System.out::println);
    }
输出结果为:

4. #和 $使用

2.1  #使用

 ( 1 ) #占位符语法

  1. #占位符会将传入的参数值自动进行预编译处理,可以防止SQL注入攻击。
  2. 使用#占位符时,Mybatis会将参数值以安全的方式替换到SQL语句中,使用JDBC的预编译语句来执行SQL查询。
  3. #占位符在生成SQL语句时会对参数值进行类型处理,将参数值转换为对应的JDBC类型。
  4. #占位符可以防止SQL注入攻击,但是无法实现动态拼接SQL片段。

( 2 ) #优点
#占位符语法在使用动态SQL时具有以下优点:

  1. 1防止SQL注入攻击:#占位符语法会将传入的参数值进行预编译处理,将参数值转换为对应的JDBC类型。这样可以防止恶意输入对SQL语句造成的安全威胁,提高了系统的安全性。
  2. 参数值类型处理:#占位符语法会对参数值进行类型处理,将参数值转换为对应的JDBC类型。这样可以避免在SQL语句中手动进行类型转换的麻烦,提高了开发效率。
  3.  可读性和可维护性:使用#占位符语法可以使SQL语句更加清晰和可读,因为参数值被封装在占位符中,不会直接出现在SQL语句中。这样可以方便后续的维护和修改,减少出错的可能性。
  4.  兼容性:#占位符语法是Mybatis的特有语法,相对于$占位符语法更具有兼容性。如果项目需要切换到其他ORM框架,使用#占位符语法可以减少代码的修改量。

综上所述,#占位符语法具有防止SQL注入攻击、参数值类型处理、可读性和可维护性、兼容性等优点。因此,在项目中使用动态SQL时,推荐使用#占位符语法。
 

2.2  $使用

 ( 1 ) $占位符语法

  1. $占位符会直接将传入的参数值替换到SQL语句中,不进行预编译处理。
  2. 使用$占位符时,Mybatis会将参数值直接替换到SQL语句中,生成最终的SQL语句。
  3. $占位符在生成SQL语句时不会对参数值进行类型处理,参数值会直接拼接到SQL语句中,可能存在安全风险。
  4. $占位符可以实现动态拼接SQL片段,但是可能存在SQL注入攻击的风险。

 ( 2 ) $优点
$占位符语法在使用动态SQL时具有以下优点:

  • 动态拼接SQL片段:$占位符语法允许在SQL语句中直接使用参数值,可以方便地进行动态拼接SQL片段。这样可以在某些特殊情况下,更灵活地构建SQL语句。
  • 字段名动态替换:$占位符语法可以用于动态替换字段名。这在某些场景下非常有用,比如需要根据用户的选择动态查询不同的字段。
  • SQL语句灵活性:$占位符语法允许在SQL语句中使用任意有效的SQL表达式。这样可以在SQL语句中进行一些复杂的计算、字符串拼接等操作。

2.3代码演示

在自动生成的 BookMapper.xml 配置文件中增加以下代码

<select id="like1" resultType="com.sy.model.Book" parameterType="java.lang.String">
    select
    <include refid="Base_Column_List" />
    from  t_mvc_book
    where bname like #{bname}
  </select>

  <select id="like2" resultType="com.sy.model.Book" parameterType="java.lang.String">
    select
    <include refid="Base_Column_List" />
    from  t_mvc_book
    where bname like '${bname}'
  </select>

  <select id="like3" resultType="com.sy.model.Book" parameterType="java.lang.String">
    select
    <include refid="Base_Column_List" />
    from  t_mvc_book
    where bname like concat('%',#{bname}, '%')
  </select>

自己在配置文件中根据自己需求来进行编写动态SQL

注意 : 

这里如果使用$占位符语法的话需要在${bname}的左右增加单引号 列如:  '${bname}' 

这已是$占位符语法的一个小缺陷,在我们日常使用中一般使用的是第三种方法( like03 )

在自动生成的 BookMapper 接口中增加以下代码

   //增加模糊查询方法
    List<Book> like1(@Param("bname")String bname);
    List<Book> like2(@Param("bname")String bname);
    List<Book> like3(@Param("bname")String bname);

编写动态SQL后进行封装方法就是在自己创建的接口中增加以下代码


    List<Book> like1(String bname);
    List<Book> like2(String bname);
    List<Book> like3(String bname);

 在创建的实现类中增加以下代码


    @Override
    public List<Book> like1(String bname) {
        return bm.like1(bname);
    }

    @Override
    public List<Book> like2(String bname) {
        return bm.like2(bname);
    }

    @Override
    public List<Book> like3(String bname) {
        return bm.like3(bname);
    }

在测试类中进行测试  

 @Test
    public void testlike1(){
        bookBiz.like1("%不死不灭%").forEach(System.out::println);
    }

    @Test
    public void testlike2(){
        bookBiz.like1("%不死不灭%").forEach(System.out::println);
    }
    @Test
    public void testlike3(){
        bookBiz.like1("%不死不灭%").forEach(System.out::println);
    }

结果展示: 

like1:

like2: 

like3:

 

5.resultType及resultMap的区别

resultType是指定查询结果的类型。它可以是任何Java类,包括基本数据类型、自定义POJO类或者集合类。当使用resultType时,MyBatis会自动将查询结果映射到指定的Java对象上。例如,如果查询结果是一个整数,则可以将resultType设置为Integer;如果查询结果是一个用户对象的列表,则可以将resultType设置为List。

<select id="getUser" resultType="com.example.User">
  SELECT id, username, email FROM user WHERE id = #{id}
</select>

resultMap是一种更灵活和强大的方式来映射查询结果。它允许我们通过定义映射规则来控制如何将数据库中的列映射到Java对象的属性上。通过使用resultMap,我们可以实现更复杂的映射逻辑,例如处理数据库列名和Java属性名不一致的情况,处理关联查询结果等。在resultMap中,我们可以定义多个映射规则,并且可以重用这些规则。

<resultMap id="userResultMap" type="com.example.User">
 <id property="id" column="user_id"/>
 <result property="username" column="user_name"/>
 <result property="email" column="user_email"/>
</resultMap>
 
<select id="getUser" resultMap="userResultMap">
 SELECT id as user_id, username as user_name, email as user_email FROM user WHERE id = #{id}
</select>

5.1区别:

  • resultType用于简单的结果映射,适用于查询结果列与Java对象属性名一致的情况,自动进行映射。
  • resultMap用于复杂的结果映射,适用于查询结果列与Java对象属性名不一致或需要自定义映射关系的情况,需要手动定义映射关系。

5.2代码演示:

在自动生成的 BookMapper.xml 配置文件中增加以下代码

<select id="List1" resultType="com.sy.model.Book">
select
<include refid="Base_Column_List" />
from  t_mvc_book
where bid=#{bid,jdbcType=INTEGER}
</select>

<select id="List2" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from  t_mvc_book
where bid=#{bid,jdbcType=INTEGER}
</select>

在自动生成的 BookMapper 接口中增加以下代码

    List<Book> List1();
    List<Book> List2();

在创建的接口  BookBiz 中增加以下代码

    List<Book>  BookList01();
    List<Book>  BookList02();

在创建的实现类  BookBizImpl 中增加以下代码

  @Override
    public List<Book> List1() {
        return bm.List1();
    }

    @Override
    public List<Book> List2() {
        return bm.List2();
    }

在测试类 增加以下代码 进行测试

   @Test
    public void List1(){
        bookBiz.List1().forEach(System.out::println);
    }

    @Test
    public void List2(){
        bookBiz.List2().forEach(System.out::println);
    }

结果展示: 

List1:

List2:

 

5.3总结:

resultType适用于简单的结果映射,可以自动进行映射;

resultMap适用于复杂的结果映射,需要手动定义映射关系。

根据具体的需求和情况,选择合适的配置项来实现查询结果的映射。

 

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

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

相关文章

RabbitMQ 消费者

RabbitMQ的消费模式分两种&#xff1a;推模式和拉模式&#xff0c;推模式采用Basic.Consume进行消费&#xff0c;拉模式则是调用Basic.Get进行消费。   消费者通过订阅队列从RabbitMQ中获取消息进行消费&#xff0c;为避免消息丢失可采用消费确认机制 消费者 拉模式拉模式的实…

ChatGPT应用于高职教育的四大潜在风险

目前&#xff0c;ChatGPT还是一种仍未成熟的技术&#xff0c;当其介入高职教育生态后&#xff0c;高职院校师生在享受ChatGPT带来的便利的同时&#xff0c;也应该明白ChatGPT引发的风险也会随之进入高职教育领域&#xff0c;如存在知识信息、伦理意识与学生主体方面的风险与挑战…

轻松正确使用代理IP

Hey&#xff0c;亲爱的程序员小伙伴们&#xff01;在进行爬虫时&#xff0c;你是否曾使用过别人的代理IP&#xff1f;是否因此慌乱&#xff0c;担心涉及违法问题&#xff1f;不要惊慌&#xff01;今天我将和你一起揭开法律迷雾&#xff0c;为你的爬虫之路保驾护航。快跟上我的节…

C++核心编程——类和对象(二)、友元、多态、文件操作

C对象模型和this指针 4.3.1 成员变量和成员函数分开存储 在C中&#xff0c;类内的成员变量和成员函数分开存储 只有非静态成员变量才属于类的对象上 空类&#xff08;类里面是空的&#xff09;&#xff0c;空对象占用内存空间为&#xff1a;1字节。 静态成员变量&#xff0…

简单屏幕共享 通过web screego windows 生成证书

生成证书用 linux 生成&#xff0c;在 windows 下使用 windows 生成证书 https://juejin.cn/post/6925006735933440014 下载地址 https://github.com/screego/server/releases 修改完配置后&#xff0c;运行 screego serve 需要修改的几个地方 # 局域网 ip 或公网 ip&…

PHP请求API接口对接电商平台亚马逊国际站按关键字搜索商品案例

关键词搜索商品API接口的用途主要包括以下几个方面&#xff1a; 实现商品搜索&#xff1a;通过关键词搜索商品API接口&#xff0c;电商平台可以为消费者提供一个简单、快捷的商品搜索功能。用户只需输入关键词&#xff0c;就可以得到与该关键词相关的商品列表。 提供便捷的商…

vue 转盘抽奖功能,可控制抽奖概率

实现逻辑&#xff1a; 思路&#xff1a;首先需要一个转盘&#xff0c;然后需要一个抽奖按钮定位在中间&#xff0c;图片提前设计或者用背景颜色代替&#xff08;这里用的是图片&#xff0c;然后计算概率&#xff09;&#xff0c;使用css完成转动效果&#xff0c;每次转动完成之…

谈谈收音机的发展

目录 1.什么是收音机 2.收音机的工作原理 3.收音机的发展历史 4.收音机的历史作用 1.什么是收音机 收音机是一种电子设备&#xff0c;用于接收和播放广播电台的无线电信号。它是人们获取各种音乐、新闻、娱乐和其他广播节目的常用设备。 收音机通常由以下几个部分组成&…

无涯教程-PHP - 简介

PHP 7是最期待的&#xff0c;它是PHP编程语言的主要功能版本。 PHP 7于2015年12月3日发布。本教程将以简单直观的方式教您PHP 7的新功能及其用法。 无涯教程假设您已经了解旧版本的PHP&#xff0c;现在就可以开始学习PHP 7的新功能。 使用下面的示例- <html><head&…

【学会动态规划】摆动序列(27)

目录 动态规划怎么学&#xff1f; 1. 题目解析 2. 算法原理 1. 状态表示 2. 状态转移方程 3. 初始化 4. 填表顺序 5. 返回值 3. 代码编写 写在最后&#xff1a; 动态规划怎么学&#xff1f; 学习一个算法没有捷径&#xff0c;更何况是学习动态规划&#xff0c; 跟我…

优化学习体验是在线培训系统的关键功能

在线培训系统是当今教育领域的一个重要工具&#xff0c;帮助学生和教师提高学习效果和教学质量。一个功能完善的在线培训系统可以提供丰富多样的学习资源和交互方式&#xff0c;以满足不同学生的需求。 个性化学习路径 每个学生的学习需求和进度都不同。通过个性化学习路径功…

【Python机器学习】实验16 卷积、下采样、经典卷积网络

文章目录 卷积、下采样、经典卷积网络1. 对图像进行卷积处理2. 池化3. VGGNET4. 采用预训练的Resnet实现猫狗识别 TensorFlow2.2基本应用5. 使用深度学习进行手写数字识别 卷积、下采样、经典卷积网络 1. 对图像进行卷积处理 import cv2 path data\instance\p67.jpg input_…

AMBA总线协议(7)——AHB(五):传输仲裁

一、前言 在之前的文章中我们讨论了AHB的很多传输细节&#xff0c;主要有控制信号&#xff0c;地址信号的译码&#xff0c;从机的响应等&#xff0c;其中重点介绍了双周期响应&#xff0c;最后介绍了数据总线及端结构&#xff0c;在本文中我们将继续介绍AHB传输的仲裁机制。 仲…

利用大模型反馈故障的解决方案

背景 观测云有两个错误巡检脚本&#xff0c;RUM 错误巡检和 APM 错误巡检&#xff0c;代码均开源。 错误巡检的主要目的是发现新出现的错误消息(error stack)&#xff0c;原有的巡检在上报了相应的事件报告后&#xff0c;只是定位了问题&#xff0c;并没有给出合适的解决方案。…

数据分析实战│价格预测挑战【文末赠书】

文本分析是指对文本信息的表示及特征项的选取&#xff0c;商品文本的描述能够反映特定立场、观点、价值和利益。考虑到网上海量的商品数量&#xff0c;对产品的定价难度很大&#xff0c;因此可以使用商品描述帮助商户定价。比如&#xff0c;服装具有较强的季节性价格趋势&#…

PHP 创业感悟交流平台系统mysql数据库web结构apache计算机软件工程网页wamp

一、源码特点 PHP 创业感悟交流平台系统&#xff08;含论坛&#xff09;是一套完善的web设计系统&#xff0c;对理解php编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 源码下载&#xff1a; https://download.csdn.…

C++中cin >> str 和 string类的getline(cin, str) 用来读取用户输入的两种不同方式的不同点

C中cin >> str 和 string类的getline(cin, str) 用来读取用户输入的两种不同方式的不同点 在C中&#xff0c;string类是标准库提供的字符串类&#xff0c;它可以帮助我们处理和操作字符串。它在<string>头文件中定义。string类提供了一系列成员函数和操作符&#…

Numpy入门(5)—应用举例

NumPy应用举例 5.1 计算激活函数Sigmoid和ReLU 使用ndarray数组可以很方便的构建数学函数&#xff0c;并利用其底层的矢量计算能力快速实现计算。下面以神经网络中比较常用激活函数Sigmoid和ReLU为例&#xff0c;介绍代码实现过程。 计算Sigmoid激活函数 计算ReLU激活函数 使…

C++ vector模拟实现

建议将vector的模拟实现写在头文件中&#xff0c;测试使用部分写在.cpp文件中 vector是类模板&#xff0c;被封装在命名空间中 部分源码&#xff1a;&#xff08;删除某些内容后&#xff09; vector模拟实现的代码&#xff1a; #include<assert.h> namespace djx {tem…

【Git分支操作---讲解二】

Git分支操作---讲解二 查看分支创建分支切换分支修改分支切换分支合并分支合并分支【冲突】(只会修改主分支不会修改其他分支)什么时候会有冲突&#xff1f; 查看分支 创建分支 切换分支 修改分支 切换分支 合并分支 合并分支【冲突】(只会修改主分支不会修改其他分支) 什么时…