• 使用mybatis实现CRUD(超详细)


    首先我们先取一个项目:
    在这里插入图片描述

    一、配置环境实现CRUD

    1.环境准备

    数据库表(tb_brand)及数据准备:

    -- 删除tb_brand表 
    drop table if exists tb_brand; 
    -- 创建tb_brand表 
    create table tb_brand ( 
      -- id 主键 
      id int primary key auto_increment, 
      -- 品牌名称 
      brand_name varchar(20), 
      -- 企业名称 
      company_name varchar(20), 
      -- 排序字段 
      ordered int, 
      -- 描述信息 
      description varchar(100), 
      -- 
      状态:0:禁用 1:启用
      status int );
      -- 添加数据 
      insert into tb_brand (brand_name, company_name, ordered, description, status) values 
      ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0), 
      ('华为', '华为技术有限公司', 100, '华为致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联 的智能世界', 1),
       ('小米', '小米科技有限公司', 50, 'are you ok', 1);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    实体类 Brand:

    public class Brand {
        // id 主键
        private Integer id;
        // 品牌名称
        private String brandName;
        // 企业名称
        private String companyName;
        // 排序字段
        private Integer ordered;
        // 描述信息
        private String description;
        // 状态:0:禁用  1:启用
        private Integer status;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    安装 MyBatisX 插件:
    MybatisX 是一款基于 IDEA 的快速开发插件,为效率而生。

    主要功能:
    XML映射配置文件 和 接口方法 间相互跳转。
    根据接口方法生成 statement。

    在没有MybatisX前,因为接口方法要跟XML文件中的select标签中的id要对应,因此会在XML文件和接口中来回切换,观察是否对应。安装了MybatisX后就解决了这一问题。
    在这里插入图片描述
    插件效果:
    在这里插入图片描述
    红色头绳的表示映射配置文件,蓝色头绳的表示mapper接口。在mapper接口点击红色头绳的小鸟图标会自动跳转到对应的映射配置文件,在映射配置文件中点击蓝色头绳的小鸟图标会自动跳转到对应的mapper接口。也可以在mapper接口中定义方法,自动生成映射配置文件中的 statement ,如图所示:
    在这里插入图片描述

    2.查询所有数据

    要完成Mybatis的操作步骤:
    1.创建接口,编写接口方法
    2.创建对应的XML文件,XML文件要与对应的接口在同一目录下,再在XML中编写SQL
    3.创建一个普通类,执行对应的SQL方法,获得返回值。

    具体步骤可以参考上一篇mybatis(1)。

    但是这样有一个小问题,当我们去打印获取到的数据的时候,有:
    在这里插入图片描述
    但是数据库中的对应的值并不是null,我们发现此时Brand实体类中brandName是驼峰命名,而数据库中对应的属性名字是brand_name,此时名字不相同就不能自动的给相应的Brand对象赋值。

    为了解决这个问题,可以在查询的时候给查询的字段用as 关键字设置别名,就可以做到数据库中查询出来的字段跟Brand里面属性的字段对应起来。如:
    在这里插入图片描述
    此时打印出来的结果就不为null了。
    但是这么做有缺点,每次查询的时候都要起别名。为此,我们可以引入sql片段:
    sql片段可以对我们查询的语句做一个记录,当用到这条语句的时候,就采用include标签引入sql片段即可。
    在这里插入图片描述
    但是sql片段也有缺点:他很不灵活。如:我们只需要brand_name的字段时,我们要设置一个sql片段;当我们需要brand_name和其它字段时,又要设置sql片段,就很麻烦。

    此时就引入一个resultMap:这个resultMap可以做到映射的作用。

    在映射配置文件中使用resultMap定义 字段 和 属性 的映射关系:

    resultMap后的id,是resultMap的唯一标识。type是实体类的名字,支持别名。
    result中的column对应的是数据库中列名的名字。property是映射到实体类中的属性名。
    在这里插入图片描述
    注:在上面只需要定义 字段名 和 属性名 不一样的映射,而一样的则不需要专门定义出来。
    在ResultMap中映射好关系后,XML文件中的SQL语句就可以正常写了:

    <select id="selectAll" resultMap="brandResultMap">
    <!--此处的resultType改为resultMap-->
                select
                    *
                from tb_brand ;
        </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    注:select标签中,在没有使用resultMap时,是resultType属性。而现在需要改为resultMap属性,后面紧跟的是resultMap的id。

    3.查看详情

    查看详情,无非就是根据数据库中,他在某个表中的id字段来获取。
    那么要在传入id字段,在BrandMapper中有:Brand selectById(int id);
    而对应地,在BrandMapper.xml中设置:

    <select id="selectById" resultMap="brandResultMap">
       select * from tb_brand where id = #{id};
    </select>
    
    • 1
    • 2
    • 3

    编写测试方法,在测试方法中执行SQL:

    public class MybatisTest {
        public static void main(String[] args) throws IOException {
            int id = 1 ;
    
            //加载mybatis的核心配置文件,获取sqlSessionFactory
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    
            //2.获取sqlSessionFactory,执行sql
            SqlSession sqlSession = sqlSessionFactory.openSession();
    
            //3.1 获取UserMapper接口的代理对象
            BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
            Brand brand = brandMapper.selectById(id);
            System.out.println(brand);
            sqlSession.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    执行测试方法结果如下:
    可以看到id后面的#{id} 被替换成了?,就等同于JDBC的sql代码了。
    在这里插入图片描述
    下面就讲到关于#的参数占位符。

    4.参数占位符

    mybatis提供了两种参数占位符:

    • #{} :执行SQL时,会将 #{} 占位符替换为?,将来自动设置参数值。从上述例子可以看出使用#{} 底层使用的是PreparedStatement。

    • ${} :拼接SQL。底层使用的是 Statement ,会存在SQL注入问题。

    如下图将 映射配置文件中的 #{} 替换成 ${} 来看效果:
    在这里插入图片描述
    可以发现,此时id后面直接就跟着1,是传入的参数。就引入了SQL注入的问题。

    因此我们最好用#{} 。

    5.SQL语句中特殊字段处理

    以后肯定会在SQL语句中写一下特殊字符,比如某一个字段大于某个值,如下图:
    在这里插入图片描述
    可以看出报错了,因为映射配置文件是xml类型的问题,而 > < 等这些字符在xml中有特殊含义,所以此时我们需要将这些符号进行转义,可以使用以下两种方式进行转义。

    1.转义字符
    在这里插入图片描述
    2.CDATA
    在XML中打入CD,就有提示,如下图输入一个< 即可。
    在这里插入图片描述

    6.多条件查询

    对于多条件的查询,可以有三种方法:1.用@Param注释来关联参数。2.实例化实体类传参。3.用Map装入SQL语句对应的字段名和值。
    如下图:如果想在多个数据中查看某一类数据,就需要进行多条件的查询来限定:
    而我们做这个功能需要分析最终的SQL语句应该是什么样,思考两个问题:1.条件表达式。2.如何连接。
    在这里插入图片描述
    条件字段 企业名称 和 品牌名称 需要进行模糊查询,所以条件应该是:
    在这里插入图片描述
    简单的分析后,我们来看功能实现的步骤:
    1.编写接口方法:
    参数:所有查询条件
    结果:List
    2.在映射配置文件中编写SQL语句
    3.编写测试方法并执行

    1.编写接口方法:

    //使用 @Param("参数名称") 标记每一个参数,在映射配置文件中就需要使用 #{参数名称} 进行占位
    List<Brand> selectByCondition(@Param("status")int status,@Param("companyName")String companyName,@Param("brandName")String brandName);
    
    //将多个参数封装成一个 实体对象 ,将该实体对象作为接口的方法参数。该方式要求在映射配置文件的SQL中使用 #{内 容} 时,里面的内容必须和实体类属性名保持一致。
    List<Brand> selectByCondition(Brand brand);
    
    //将多个参数封装到map集合中,将map集合作为接口的方法参数。该方式要求在映射配置文件的SQL中使用 #{内容}时,里面的内容必须和map集合中键的名称一致。
    List<Brand> selectByCondition(Map map);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2.编写SQL语句
    在 BrandMapper.xml 映射配置文件中编写 statement ,使用 resultMap 而不是使用 resultType

        <select id="selectByCondition" resultMap="brandResultMap">
            select * from tb_brand where
            status = #{status} and company_name like #{companyName}
            and brand_name like #{brandName};
        </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3.编写测试方法
    在 test/java 下的 com.itheima.mapper 包下的 MybatisTest类中 定义测试方法:

    @Test
        public void testSelectByCondition() throws IOException {
            int status = 1;
            String companyName = "%"+"华为"+"%";
            String brandName = "%"+"华为"+"%";
    
            //加载mybatis的核心配置文件,获取sqlSessionFactory
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    
            //2.获取sqlSessionFactory,执行sql
            SqlSession sqlSession = sqlSessionFactory.openSession();
    
            //3.1 获取UserMapper接口的代理对象
            BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
            List<Brand> brands = brandMapper.selectByCondition(status,companyName,brandName);
            System.out.println(brands);
            sqlSession.close();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    注:这里的多条件查询要用到模糊匹配,此处设置的company和brandName要设置为模糊匹配的条件。这里传入的就对应到接口方法中要传入的参数。
    在这里插入图片描述

    7.动态SQL

    上述功能实现存在很大的问题。用户在输入条件时,肯定不会所有的条件都填写,这个时候我们的SQL语句就不能那样写的。SQL语句会根据用户输入的条件自己地变动和适应。

    针对上述的需要,Mybatis对动态SQL有很强大的支撑:

    if
    choose (when, otherwise)
    trim (where, set)
    foreach

    实现动态SQL,只需要在xml文件下修改对应的SQL语句即可。
    如:用户如果输入了 当前状态 和 企业名称 时,SQL语句是select * from tb_brand where status = #{status} and company_name like #{companName},那么如何在原来SQL语句的基础上变动呢?
    可以用到Mybatis提供的if标签:if标签中的test属性写的是条件。

    <select id="selectByCondition" resultMap="brandResultMap">
          select * from tb_brand where
          <if test="status!=null">
              status = #{status}
          </if>
          <if test="companyName==null and companyName!=''">
              and company_name like #{companyName}
          </if>
          <if test="brandName!=null and brandName!=''">
              and brand_name like #{brandName}
          </if>
    </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    此时我们只传入status和companyName时,是可以进行查询的,没有报错。
    但是我们只传入companyName时,却报错了。

    原因很简单:我们发现上面的SQL语句中,如果只有companyName属性,SQL语句就变为:select * from tb_brand where and company_name like ?,此时只有一个条件时,有and 是错误的。此时删除and当有两个条件以上时却又行不通,因此删and又不是,不删and又不是。

    为此,Mybatis中有where标签帮助我们解决这个问题:
    注:在status的条件语句前也要加上and,当只有一个条件时,Mybatis的where标签会帮我们自动地删掉and。

    <select id="selectByCondition" resultMap="brandResultMap">
          select * from tb_brand 
          <where>
              <if test="status!=null">
                  and status = #{status}
              </if>
              <if test="companyName==null and companyName!=''">
                  and company_name like #{companyName}
              </if>
              <if test="brandName!=null and brandName!=''">
                  and brand_name like #{brandName}
              </if>
          </where>
    </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    7.单条件查询

    在这里插入图片描述
    如上图所示,在查询时只能选择 品牌名称 、 当前状态 、 企业名称 这三个条件中的一个,但是用户到底选择哪儿一个,我们并不能确定。这种就属于单个条件的动态SQL语句。

    这种需求需要使用到 choose(when,otherwise)标签 实现, 而 choose 标签类似于Java 中的switch语句。

    通过一个案例来使用这些标签:
    1.编写接口方法

    List<Brand> selectByConditionSingle(Brand brand);
    
    • 1

    2.编写SQL语句

    <select id="selectByCondition" resultMap="brandResultMap">
        select * from tb_brand
        <where>
            <if test="status!=null">
                and status = #{status}
            </if>
            <if test="companyName!=null and companyName!=''">
                and company_name like #{companyName}
            </if>
            <if test="brandName!=null and brandName!=''">
                and brand_name like #{brandName}
            </if>
        </where>
    </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3.编写测试类
    此处跟多条件查询的几乎类似,只是设置实例化brand的时候,只设置一个参数。

    结果:
    在这里插入图片描述
    当然,用户可能什么也不输入,此时如果是按照上面的SQL语句进行查询,会报错。因此要处理什么都不查询的时候错误。(只需要加上otherwise即可,条件为1=1):

        <select id="selectByConditionSingle" resultMap="brandResultMap">
            select * from tb_brand
            <where>
                <choose>
                    <when test="status!=null">
                        status = #{status}
                    </when>
                    <when test="companyName!=null and companyName!=''">
                        company_name like #{companyName}
                    </when>
                    <when test="brandName!=null and brandName!=''">
                        brand_name like #{brandName}
                    </when>
                    <otherwise>
                        1==1
                    </otherwise>
                </choose>
            </where>
        </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    当然,我们要灵活的使用where标签,就可以不再使用otherwise了,Mybatis就可以把上面的otherwise规避的问题自动解决了。

    8.添加数据

    编写接口方法:

    void add(Brand brand);
    
    • 1

    编写SQL语句:

    <insert id="add">
        insert into tb_brand(brand_name, company_name, ordered, description, status)
        values (#{brandName},#{companyName},#{ordered},#{description},#{status});
    </insert>
    
    • 1
    • 2
    • 3
    • 4

    编写测试代码:

    @Test
        public void addTest() throws IOException {
            int status = 1;
            String companyName = "波导手机";
            String brandName = "波导";
            String description = "手机中的战斗机";
            int ordered = 100;
            Brand brand = new Brand();
            brand.setCompanyName(companyName);
            brand.setBrandName(brandName);
            brand.setDescription(description);
            brand.setOrdered(ordered);
            //加载mybatis的核心配置文件,获取sqlSessionFactory
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    
            //2.获取sqlSessionFactory,执行sql
            SqlSession sqlSession = sqlSessionFactory.openSession();
    
            //3.1 获取UserMapper接口的代理对象
            BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
            brandMapper.add(brand);
            sqlSession.close();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    我们运行测试的代码,可以发现运行没有报错。但是从数据库中查看这条数据是否已经插入时,却没有查到。
    我们查看运行的结果:
    看到了自动提交事务的操作是没有开启的,并且帮我们回滚了事务。
    在这里插入图片描述
    为了解决这个问题,有两个解决办法:
    1.手动提交事务:在测试代码中调用了上面的add方法后,就sqlSession.commit();来手动提交事务。
    2.自动提交事务:在获取sqlSession时,传入一个true参数:SqlSession sqlSession = sqlSessionFactory.openSession(true);

    添加——主键返回:
    在数据添加成功后,有时候需要获取插入数据库数据的主键(主键是自增长)。
    比如:添加订单和订单项,如下图就是京东上的订单:
    在这里插入图片描述
    订单数据存储在订单表中,订单项存储在订单项表中。假设我们添加了一个订单后,此时要添加订单项,订单项的id要与订单对应,但是此时拿不到订单的id就非常麻烦。

    我们可以简单地演示一下:在上面的测试代码中,等到调用add方法后,去获取我们实例化的brand的id后,打印的结果是null。
    解决方法:
    在statement中添加两个属性:
    useGenerateKeys:是够获取自动增长的主键值。true表示获取
    keyProperty :指定将获取到的主键值封装到哪个属性里
    在这里插入图片描述
    此时再去测试代码中调用add方法后,打印实例化好的brand的id时,就可以打印出来了。

    9.修改字段

    9.1 修改全部字段

    1.编写接口

    int update(Brand brand);
    
    • 1

    2.编写SQL语句

    <update id="update">
        update tb_brand set brand_name = #{brandName},
                            company_name = #{companyName},
                            ordered = #{ordered},
                            description = #{description},
                            status = #{status}
        where id = #{id};
    </update>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.编写测试代码:

    @Test
        public void testUpdate() throws IOException {
            int status = 1;
            String companyName = "波导手机";
            String brandName = "波导";
            String description = "波导手机,手机中的战斗机";
            int ordered = 200;
            int id = 5;
    
            Brand brand = new Brand();
            brand.setCompanyName(companyName);
            brand.setBrandName(brandName);
            brand.setDescription(description);
            brand.setOrdered(ordered);
            brand.setId(id);
            //加载mybatis的核心配置文件,获取sqlSessionFactory
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    
            //2.获取sqlSessionFactory,执行sql
            SqlSession sqlSession = sqlSessionFactory.openSession();
    
            //3.1 获取UserMapper接口的代理对象
            BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
            int ret = brandMapper.update(brand);
            System.out.println(ret);
            sqlSession.close();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    9.2 修改动态字段

    在这里插入图片描述
    如图所示是修改页面,用户在该页面书写需要修改的数据,点击 提交 按钮,就会将数据库中对应的数据进行修改。注意一点,如果哪儿个输入框没有输入内容,我们是将表中数据对应字段值替换为空白还是保留字段之前的值?答案肯定是保留之
    前的数据。

    编写的接口不变,只需要修改对应的SQL语句即可。
    如下代码:但是会发现两个问题:
    1.如果status没有传入,则description就是最后一个条件语句,但是它的后面有逗号,SQL语句就报错了。
    2.如果传入的东西都为空,则SQL语句还是会报错,set后面就没有东西了。

        <update id="update">
            update tb_brand set
            <if test="brandName!=null and brandName!=''">
                brand_name = #{brandName},
            </if>
            <if test="companyName!=null and companyName!=''">
                company_name = #{companyName},
            </if>
            <if test="ordered!=null and ordered!=''">
                ordered = #{ordered},
            </if>
            <if test="description!=null and description!=''">
                description = #{description},
            </if>
            <if test="status!=null">
                status = #{status}
            </if>
            where id = #{id};
        </update>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    我们可以使用set标签来解决上面的问题:

        <update id="update">
            update tb_brand
                <set>
                    <if test="brandName!=null and brandName!=''">
                        brand_name = #{brandName},
                    </if>
                    <if test="companyName!=null and companyName!=''">
                        company_name = #{companyName},
                    </if>
                    <if test="ordered!=null and ordered!=''">
                        ordered = #{ordered},
                    </if>
                    <if test="description!=null and description!=''">
                        description = #{description},
                    </if>
                    <if test="status!=null">
                        status = #{status}
                    </if>
            </set>
            where id = #{id};
        </update>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    10.删除操作

    10.1 删除一行数据

    如上图所示,每行数据后面都有一个 删除 按钮,当用户点击了该按钮,就会将改行数据删除掉。那我们就需要思考,这种删除是根据什么进行删除呢?是通过主键id删除,因为id是表中数据的唯一标识。

    1.编写接口:

    void deleteByIds(@Param("ids") int[] ids);
    
    • 1

    2.编写SQL语句:

        <delete id="delete">
            delete from tb_brand where id = #{id};
        </delete>
    
    • 1
    • 2
    • 3

    3.编写测试代码:

    @Test
        public void testDelete() throws IOException {
            int id = 5;
    
            Brand brand = new Brand();
            brand.setId(id);
            //加载mybatis的核心配置文件,获取sqlSessionFactory
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    
            //2.获取sqlSessionFactory,执行sql
            SqlSession sqlSession = sqlSessionFactory.openSession();
    
            //3.1 获取UserMapper接口的代理对象
            BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
            int ret = brandMapper.delete(brand);
            System.out.println(ret);
            sqlSession.close();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    10.2 批量删除

    对于批量删除,因为删除是根据id来删除的,因此就要设置id数组来进行遍历地删除。

    在 BrandMapper.xml 映射配置文件中编写删除多条数据的 statement 。
    编写SQL时需要遍历数组来拼接SQL语句。Mybatis 提供了 foreach 标签供我们使用
    编写SQL语句。

    foreach 标签:
    用来迭代任何可迭代的对象(如数组,集合)。

    • collection 属性:
      mybatis会将数组参数,封装为一个Map集合。
      默认:array = 数组,即map的key为array,map的value为数组。
      使用@Param注解改变map集合的默认key的名称。当没有用@Param注解时,collection填的是array,否则运行测试代码时会报错。

    • item 属性:本次迭代获取到的元素。

    • separator 属性:集合项迭代之间的分隔符。 foreach 标签不会错误地添加多余的分隔符。也就是最后一次迭代不会加分隔符。

    • open 属性:该属性值是在拼接SQL语句之前拼接的语句,只会拼接一次

    • close 属性:该属性值是在拼接SQL语句拼接后拼接的语句,只会拼接一次

    <delete id="deleteByIds">
            delete from tb_brand where id in
            <foreach collection="ids" item="id" separator="," open="(" close=")">
                #{id}
            </foreach>
             ;
        </delete>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    假如数组中的id数据是{1,2,3},那么拼接后的sql语句就是:

    delete from tb_brand where id in (1,2,3);
    
    • 1

    可以看到是比较繁杂的。

    编写测试代码:

    @Test
        public void testDeleteByIds() throws IOException {
            int[] ids = {5,7,8};
            //加载mybatis的核心配置文件,获取sqlSessionFactory
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    
            //2.获取sqlSessionFactory,执行sql
            SqlSession sqlSession = sqlSessionFactory.openSession();
    
            //3.1 获取UserMapper接口的代理对象
            BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
            brandMapper.deleteByIds(ids);
            sqlSession.close();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    10.单个/多个参数传递方式

    Mybatis 接口方法中可以接收各种各样的参数,如下:
    1.多个参数
    2.单个参数:单个参数又可以是如下类型:
    POJO 类型
    Map 集合类型
    Collection 集合类型
    List 集合类型
    Array 类型
    其他类型

    10.1 多个参数的传递方式

    在本篇博客中就提到,多个参数的传递方式有:用@Param注解、传入参数为实例化的实例类、传入参数为Map。

    为了了解为什么要加入该注释,就需要了解Mybatis实现的源码。
    如:

    User select(@Param("username") String username,@Param("password") String password);
    
    • 1

    <select id="select" resultType="user"> 
    	select * from tb_user whereusername=#{username} and password=#{password} 
    </select>
    
    • 1
    • 2
    • 3

    我们在接口方法中定义多个参数,Mybatis 会将这些参数封装成 Map 集合对象,值就是参数值,而键在没有使用 @Param注解时有以下命名规则:

    1.以 arg 开头 :第一个参数就叫 arg0,第二个参数就叫 arg1,以此类推。如:

    map.put("arg0",参数值1);
    map.put("arg1",参数值2);
    
    • 1
    • 2

    2.以 param 开头 : 第一个参数就叫 param1,第二个参数就叫 param2,依次类推。如:

    map.put("param1",参数值1);
    map.put("param2",参数值2);
    
    • 1
    • 2

    我们可以验证一下:
    在 UserMapper 接口中定义如下方法:

    User select(String username,String password);
    
    • 1

    在 UserMapper.xml 映射配置文件中定义SQL:

    <select id="select" resultType="user"> 
    select * from tb_user whereusername=#{arg0} and password=#{arg1} </select>
    
    或者
    
    <select id="select" resultType="user"> 
    select * from tb_user whereusername=#{param1} and password=#{param2} </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    运行代码结果如下:在这里插入图片描述
    在映射配合文件的SQL语句中使用用 arg 开头的和 param 书写,代码的可读性会变的特别差,此时可以使用 @Param 注解。

    在接口方法参数上使用 @Param 注解,Mybatis 会将 arg 开头的键名替换为对应注解的属性值。

    代码验证:
    在 UserMapper 接口中定义如下方法,在 username 参数前加上 @Param 注解

    User select(@Param("username") String username, String password);
    
    • 1

    Mybatis 在封装 Map 集合时,键名就会变成如下:

    map.put(“username”,参数值1);
    map.put(“arg1”,参数值2);
    map.put(“param1”,参数值1);
    map.put(“param2”,参数值2);

    在 UserMapper.xml 映射配置文件中定义SQL:

    <select id="select" resultType="user"> 
    select * from tb_user whereusername=#{username} and password=#{param2} 
    </select>
    
    • 1
    • 2
    • 3

    运行程序结果没有报错。而如果将 #{} 中的 username 还是写成 arg0:

    <select id="select" resultType="user"> 
    select * from tb_user whereusername=#{arg0} and password=#{param2} </select>
    
    • 1
    • 2

    运行程序则可以看到错误:
    在这里插入图片描述

    10.2 单个参数的传递方式

    1.POJO 类型
    直接使用。要求 属性名 和 参数占位符名称 一致

    2.Map 集合类型
    直接使用。要求 map集合的键名 和 参数占位符名称 一致

    3.Collection 集合类型
    Mybatis 会将集合封装到 map 集合中,如下:

    map.put(“arg0”,collection集合);
    map.put(“collection”,collection集合);

    4.List 集合类型
    Mybatis 会将集合封装到 map 集合中,如下:

    map.put(“arg0”,list集合);
    map.put(“collection”,list集合);
    map.put(“list”,list集合);

    可以使用 @Param 注解替换map集合中默认的 arg 键名。

    5.Array 类型
    Mybatis 会将集合封装到 map 集合中,如下:

    map.put(“arg0”,数组);
    map.put(“array”,数组);

    可以使用 @Param 注解替换map集合中默认的 arg 键名。

    6.其他类型
    比如int类型, 参数占位符名称 叫什么都可以。尽量做到见名知意。

    对于单个参数为什么可以用param和arg,这个需要查看ParamNameResolver这个类中的getNamedParams方法。

    11.注解开发

    使用注解开发会比配置文件开发更加方便。如下就是使用注解进行开发:

    @Select(value = "select * from tb_user where id = #{id}") public User select(int id);
    
    • 1

    注意:注解是用来替换映射配置文件方式配置的,所以使用了注解,就不需要再映射配置文件中书写对应的 statement。

    Mybatis 针对 CURD 操作都提供了对应的注解,已经做到见名知意。如下:
    查询 :@Select
    添加 :@Insert
    修改 :@Update
    删除 :@Delete

    注意:在官方文档中 入门 中有这样的一段话:在这里插入图片描述
    所以,注解完成简单功能,配置文件完成复杂功能

  • 相关阅读:
    springboot+jsp+ssm高校图书馆图书借阅收藏评论管理系统617w1
    【微信小程序 | 实战开发】配置微信小程序APPID并快速接入
    Redis_第二章_实战篇_第2节_商户缓存策略(缓存穿透、缓存雪崩、缓存击穿)
    电子版证件照怎么制作并改大小
    智能人体存在感知方案,毫米波雷达感应器成品,智能化感知联动应用
    Linux 磁盘挂载 磁盘卸载
    智能家居后端技术解决方案-API设计
    如何拥有自己的专属GPT-本地部署目前最强大模型llama3
    uos服务器系统安装达梦8数据库
    前端html生成PDF
  • 原文地址:https://blog.csdn.net/ZJRUIII/article/details/125265827