MyBatis学习笔记,快速入门

MyBatis

MyBatis中文官网https://mybatis.net.cn/

本篇笔记参照黑马程序员视频 教程 记录。

视频链接

黑马程序员-MyBatis快速入门

MyBatis简介

  • MyBatis是一款优秀的持久层框架,用于简化JDBC开发

持久层

  • 负责将数据保存到数据库的那一层代码就是持久层
  • JavaEE三层框架:表现层、业务层、持久层

JDBC缺点

  1. 硬编码
  2. 操作繁琐

MyBatis快速入门

步骤

  1. 创建表,添加数据
  2. 创建模块,导入坐标(MyBatis坐标、MySQL驱动坐标)
  3. 编写MyBatis核心配置文件--------》替换连接信息,解决硬编码问题
  4. 编写SQL映射文件------》统一管理SQL语句,解决硬编码问题
  5. 编码,写程序
    1. 定义POJO类
    2. 加载核心配置文件,获取SQLSessionFactory对象
    3. 获取Session对象,执行SQL语句
    4. 释放资源

第一次使用MyBatis

  1. 创建表,添加数据就不说了
  2. 在项目中导入MyBatis的jar包
  3. 在项目的resource目录下,编写mybatis的核心配置文件,MyBatis官网会有,直接复制过来即可,文件名称随意,但习惯是mybatis-config.xml,修改配置文件中的连接信息
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
<!--            连接信息-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///mybase"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
<!--    指定当前SQL映射文件-->
    <mappers>
<!--	SQL映射文件,相对路径-->        
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>

注意

  • MySQL8.0及以上版本,需要导入8.x的jar包,并且Driver地址为com.mysql.cj.jdbc.Driver, 之前版本不用变
  • url的写法,一般是jdbc:mysql://localhost:3306/数据库名,也可以这样写jdbc:mysql:///数据库名,默认就是localhost:3306
  1. 同样,在resources目录下编写SQL映射文件,这个文件也可以从官网直接复制过来,文件名称随意,但是一般都是以ClassNameMapper.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">
<!--
    namespace 命名空间
-->
<mapper namespace="test">
<!--    id是这条SQL语句的唯一标识
        resultType是返回时的封装类型
-->
<!--	对应类的全限名-->    
    <select id="selectAll" resultType="com.mybatis.Person">
        select * from user;
    </select>
</mapper>
  1. 编写数据库对应的类,并设置setter和getter方法,这个类名称一定要与SQL映射文件中的resultType相对应
package com.mybatis;

public class Person {
    private int id ;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

  1. 加载MyBatis核心配置文件,获取SqlSessionFactory对象,这个官网也是直接复制过来即可:happy:
package com.mybatis;

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 MyBatisDemo {
    public static void main(String[] args) throws IOException {
//        1.加载MyBatis核心配置文件,获取SqlSessionFactory对象
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

//        2.获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

//        3.执行SQL,对应SQL语句的 namespace.id
        List<Person> users = sqlSession.selectList("test.selectAll");

        System.out.println(users);
//          4.释放资源
        sqlSession.close();
    }
}

这就是最简单、入门的MyBatis流程了,刚开始确实感到繁琐

解决SQL语句报红提示

在入门案例映射配置文件中存在报红的情况。问题如下:

  • 产生的原因:Idea和数据库没有建立连接,不识别表信息。但是大家一定要记住,它并不影响程序的执行。
  • 解决方式:在Idea中配置MySQL数据库连接。

IDEA中配置MySQL数据库连接

  • 点击IDEA右边框的 Database ,在展开的界面点击 + 选择 Data Source ,再选择 MySQL

  • 在弹出的界面进行基本信息的填写

  • 点击完成后就能看到如下界面

    而此界面就和 navicat 工具一样可以进行数据库的操作。也可以编写SQL语句

Mapper代理开发

概述

我们刚开始写的代码,也存在类似JDBC硬编码的问题

image-20220922192908537

这个地方传递参数namespace.id仍然是硬编码,不便于后期的维护。

如果使用Mapper代理方式则不存在硬编码问题,MyBatis官网也推荐使用Mapper的代理方式。

Mapper代理开发的规则

  • 定义与SQL映射文件同名的Mapper接口,并且将Mapper接口和映射文件放置在同一目录下
  • 设置SQL映射文件的namespace.id属性为Mapper接口权限名
  • 在Mapper接口中定义方法,方法名就是SQL映射文件中的sql语句的id,并保持参数类型和返回值类型一致

实现

  1. 在源码目录下,创建Mapper包,包中创建PersonMapper接口

    image-20220922194641833

  2. 将SQL映射文件与mapper接口同目录下,有两种方法

    1. 第一种方式,我们可以直接将xml文件拖拽到mapper包下

      image-20220922194838560

      但是这样不符合我们的规范,导致目录混乱

      Maven中规定配置文件应该放置到ressources目录下

    2. 第二种方式,在resources目录下,创建与mapper接口同结构目录

      image-20220922195148292

      这样,Maven在编译时,会自动将配置文件放置到mapper接口目录下

      image-20220922200716071

    注意:在SQL映射文件中,namespace修改为对应接口的权限名,mybatis核心配置文件中映射文件的目录也要改

  3. 编写程序

    package com.mybatis;
    
    import com.mybatis.mapper.PersonMapper;
    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 MyBatisDemo02 {
        public static void main(String[] args) throws Exception {
    //          1.加载mybatis配置文件
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    
    //        2.获取SqlSession对象,用它来执行SQL语句
            SqlSession sqlSession = sqlSessionFactory.openSession();
    //        3.执行SQL
    //          3.1 获取PersonMapper接口代理对象
            PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);
            List<Person> perons = personMapper.selectAll();
    
            System.out.println(perons);
    
    //        4.关闭资源
            sqlSession.close();
        }
    }
    
    

    注意:如果Mapper接口名称和SQL映射文件名称相同,并在同一目录下,则可以在mybatis配置文件中,通过包扫描的方式简化SQL映射文件的加载

    <!--    指定当前SQL映射文件-->
        <mappers>
    <!--        <mapper resource="com/mybatis/mapper/PersonMapper.xml"/>-->
    <!--        包扫描的方式-->
            <package name="com.mybatis.mapper"/>
        </mappers>
    

核心配置文件

MyBatis的核心配置文件有这些配置

image-20220922202803780

在MyBatis的配置文件中的<configuration>下,各种不同的标签应该按照这样的特点定的前后顺序来放置

environments

在核心配置文件的environments标签中,可以配置多个environment,使用id给每个environment做标识,在environments标签中使用default=环境id来指定使用哪一个环境

这些环境可以是不同的库,甚至可以是不同品牌的数据库

    <environments default="test">
        <environment id="development">
            <transactionManager type="JDBC"/>
<!--            连接信息-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///mybase"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
        <environment id="test">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///mybase"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

类型别名

在SQL映射配置文件中,resultType属性需要我们填写类的全限定名,特别麻烦。

MyBatis提供了typeAliases可以简化这部分书写,别名不区分大小写

可以使用这种方式来为某一个特定的类起别名

<typeAliases>
  <typeAlias alias="Author" type="domain.blog.Author"/>
  <typeAlias alias="Blog" type="domain.blog.Blog"/>
  <typeAlias alias="Comment" type="domain.blog.Comment"/>
  <typeAlias alias="Post" type="domain.blog.Post"/>
  <typeAlias alias="Section" type="domain.blog.Section"/>
  <typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>

我们还可以使用包扫描的方式来为包下的每一个类起一个别名,默认就是类名,且不区分大小写

    <typeAliases>
        <package name="com.mybatis"/>
    </typeAliases>

这样,在SQL映射文件中可以直接使用类的名称

    <select id="selectAll" resultType="Person">
        select * from user;
    </select>

配置文件完成增删改查

安装MyBatisX插件

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

直接在IDEA中setting —>plugins搜索安装即可

主要功能

  • XML映射配置文件和接口方法 间相互跳转
  • 根据接口方法生成statement

查询所有数据

  1. 编写Mapper接口

    package com.mybatis.mapper;
    
    import com.mybatis.pojo.Brand;
    
    import java.util.List;
    
    public interface BrandMapper {
        List<Brand> selectAll();
    }
    
    
  2. 编写SQL映射文件

    <?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">
    <!--
        namespace 命名空间
    -->
    <mapper namespace="com.mybatis.mapper.BrandMapper">
        <!--    id是这条SQL语句的唯一标识
                resultType是返回时的封装类型
        -->
        <select id="selectAll" resultType="Brand">
            select * from tb_brand;
        </select>
    
    </mapper>
    
  3. 编写测试程序

    package com.mybatisTest;
    
    import com.mybatis.mapper.BrandMapper;
    import com.mybatis.pojo.Brand;
    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 org.junit.Test;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.List;
    
    public class testMybatis {
    
        @Test
        public void testSelectAll() throws IOException {
            //          1.加载mybatis配置文件
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    
    //        2.获取SqlSession对象
            SqlSession sqlSession = sqlSessionFactory.openSession();
    //        3.获取对应的mapper
            BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
    //          4.执行SQL
            List<Brand> brands = mapper.selectAll();
            System.out.println(brands);
    //        4.释放资源
            sqlSession.close();
        }
    }
    
表字段与类属性名转换

我们发现这样一个问题,查询出来的结果并没有为实体类成功赋值

image-20220922215804789

这是因为数据库中表的字段名与实体类的属性名不一致导致的

解决方法

  1. 使用别名

        <select id="selectAll" resultType="Brand">
            select id,brand_name as brandName,company_name as companyName,ordered,description,status from tb_brand;
        </select>
    

    这样是可以解决的,但是如果查询的语句多了,这样写就会非常繁琐

  2. 使用SQL片段

    我们将需要复用的SQL片段抽取到sql标签中,并为这段SQL片段设置id

    <sql id="brandColumn">id,brand_name as brandName,company_name as companyName,ordered,description,status </sql>
    

    在原来的sql语句上直接拼接即可,使用<include refid="">来引用

        <select id="selectAll" resultType="Brand">
            select <include refid="brandColumn"/> from tb_brand;
        </select>
    

    但是这种SQL片段仍然存在局限性,例如其他查询的字段名并不是这些,那么就需要重新抽取SQL片段,依然是很繁琐,不灵活

  3. 使用resultMap

    就是给数据库表的字段名与类属性名之间做一个映射

    只需要对不一样的字段做映射,使用<resultMap>来定义字段和属性的映射

        <resultMap id="mapBrand" type="brand">
            <result column="brand_name" property="brandName"></result>
            <result column="company_name" property="companyName"></result>
        </resultMap>
    

    SQL语句的返回值类型,需要指定结果映射id

        <select id="selectAll" resultMap="mapBrand">
            select * from tb_brand;
        </select>
    

查询一条数据

查看某一条具体的数据,在SQL语句中就需要传参了

  1. 编写BrandMapper接口中方法

    Brand selectById(int id);
    
  2. 编写SQL语句

    注意: 使用的是resultMap不是resultType

        <select id="selectById" resultMap="mapBrand">
            select * from tb_brand where id = #{id};
        </select>
    
  3. 编写测试方法

        @Test
        public void testSelectById() throws IOException {
            int id = 1;
            //          1.加载mybatis配置文件
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    
    //        2.获取SqlSession对象
            SqlSession sqlSession = sqlSessionFactory.openSession();
    //        3.获取对应的mapper
            BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
    //          4.执行SQL
            Brand brand = mapper.selectById(id);
            System.out.println(brand);
    //        4.释放资源
            sqlSession.close();
        }
    
参数占位符

在Mapper接口中的方法需要传入参数,在与之对应的SQL映射文件中的SQL语句需要来接收这个参数。

mybatis提供了两种参数占位符

  • #{}:执行SQL时,会将#{}占位符替换为?,将来运行时自动设置参数,底层用的是PreparedStatement

    image-20220922223735911

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

    image-20220922223823603

parameterType使用

对于有参数的mapper接口方法,我们在映射配置文件中可以使用parameterType来指定参数类型,只不过该属性可以省略

    <select id="selectById" parameterType="int" resultMap="mapBrand">
        select * from tb_brand where id = #{id};
    </select>
特殊字符处理

当sql 语句中存在特殊字符时,比如小于号<

解决方法

  • 转义字符

        <select id="selectById" parameterType="int" resultMap="mapBrand">
            select * from tb_brand where id &lt; #{id};
        </select>
    
  • <!CDATA[内容]]>

        <select id="selectById" parameterType="int" resultMap="mapBrand">
            select * from tb_brand where id 
            <![CDATA[
                <
            ]]> #{id};
        </select>
    

多条件查询

  1. 编写接口方法

    该方法有三个参数,我们就需要考虑在定义接口时,参数应该如何定义,这些参数等会传到SQL语句那,如何才能让SQL语句辨别?MyBatis针对参数有多重实现方式

  • 使用@Param("参数名称")标记一个参数,在SQL语句中需要用#{参数名称}来占位

     Brand selectByCondition(@Param("status") int status, @Param("brandName") String brandName, @Param("companyName") String companyName);
    
  • 将多个参数封装成一个实体对象,将该实体对象作为方法的参数。

    要求实体对象中的属性名与SQL语句中的#{占位符}一致

        List<Brand> selectByCondition(Brand brand);
    
  • 将这多个参数封装到Map集合中,将map集合作为方法的参数。

    同样,也是要求Map集合中的键与sql语句中的#{占位符名}保持一致

        List<Brand> selectByCondition(Map map);
    
  1. 编写SQL语句
    <select id="selectByCondition" resultMap="mapBrand">
        select *
        from tb_brand
        where status = #{status}
        and brand_name like #{brandName}
        and company_name like #{companyName};
    </select>
  1. 编写测试方法
    @Test
    public void testSelectByCondition() throws IOException {
//        假设的参数
        int status = 1;
        String brandName = "华为";
        String companyName = "华为";
        brandName = "%" + brandName + "%";
        companyName = "%" + companyName + "%";
        
//        1.加载mybatis配置文件
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

//        2.获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        
//        3.获取对应的mapper
        BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
        
//        方式一:直接传参,注解的方式
//        List<Brand> brands = mapper.selectByCondition(status, brandName, companyName);
//        List<Brand> brands = mapper.selectByCondition(brand);
        
//          方式二:封装成对象
//        Brand brand = new Brand();
//        brand.setStatus(status);
//        brand.setBrandName(brandName);
//        brand.setCompanyName(companyName);
//        List<Brand> brands = mapper.selectByCondition(brand);
        
//        方式三:封装成一个Map集合
        Map map = new HashMap<String, String>();
        map.put("status", status + "");
        map.put("brandName", brandName);
        map.put("companyName", companyName);

//          4.执行SQL
        List<Brand> brands = mapper.selectByCondition(map);
        System.out.println(brands);
//        4.释放资源
        sqlSession.close();
    }
}

动态SQL

多条动态查询

其实上面的代码处理还是有些问题:用户必须同时选择三个条件才可以查询得到。但是现实生活中,往往用户只会输入一个或两个条件,这样也应该查询出相对应的数据。

这就需要动态SQL了

当用户只输入当前状态时,SQL语句应该是这样的

select * from tb_brandd where status = #{status};

当用户只输入企业名称时,SQL语句应该是这样的

select * from tb_brand where company_name like #{companyName};

针对这种情况,就需要在SQL拼接时进行判断

MyBatis对动态SQL有很强大的支持

if

choose(when, otherwise)

trim(where,set)

foreach

  • if标签:条件判断

    • 属性:test逻辑表达式
        <!--    动态SQL查询-->
        <select id="selectByCondition" resultMap="mapBrand">
            select *
            from tb_brand
            where
            <if test="status != null">
                status = #{status}
            </if>
            <if test="brandName != null and brandName != '' ">
                and brand_name like #{brandName}
            </if>
            <if test="companyName != null and companyName != '' ">
                and company_name like #{companyName}
            </if>
            ;
        </select>
    

    查看运行结果

    image-20220923121520351

    上面的SQL语句仍然存在Bug,当我们不给status值时,SQL语句就变成了这样

    select * from and brand_name like #{brandName} and company_name like #{companyName};
    

    显然不符合sql语句的规范,会导致出错

    • 解决方案

      • 添加恒等式,像这样,SQL语句就不会出错
          <!--    动态SQL查询-->
          <select id="selectByCondition" resultMap="mapBrand">
              select *
              from tb_brand
              where   1=1
              <if test="status != null">
                  and status = #{status}
              </if>
              <if test="brandName != null and brandName != '' ">
                  and brand_name like #{brandName}
              </if>
              <if test="companyName != null and companyName != '' ">
                  and company_name like #{companyName}
              </if>
              ;
          </select>
      
      • MyBatis提供了<where>标签,可以用来替代where关键字

        MyBatis会动态的判断某个条件前面需不需要加and

         <!--    动态SQL查询-->
          <select id="selectByCondition" resultMap="mapBrand">
              select *
              from tb_brand
              <where>
              <if test="status != null">
                  and status = #{status}
              </if>
              <if test="brandName != null and brandName != '' ">
                  and brand_name like #{brandName}
              </if>
              <if test="companyName != null and companyName != '' ">
                  and company_name like #{companyName}
              </if>
              </where>
              ;
          </select>
      
单条动态查询

当用户对条件作出选择时,选择出一个,类似于Java中的switch

对于这样的switch结构,MyBatis中也是支持的

<choose>   <!--相当于switch>  -->
	<when></when>	<!--相当于case -->
    <otherwise></otherwise>	<!-- 相当于default -->
</choose>
    <select id="selectBySingleCondition" resultMap="mapBrand">
        select *
        from tb_brand
        where
        <choose>
            <when test="status != null">
                status = #{status}
            </when>
            <when test="brandName != null and brandName != '' ">
                brand_name like #{brandName}
            </when>
            <when test="companyName != null and companyName != '' ">
                company_name like #{companyName}
            </when>

        </choose>
        ;
    </select>

当用户 一个都不选的时候,我们的SQL语句就变成了这样

select * from tb_brand where;

可以通过<otherwise>来指定默认的情况

    <select id="selectBySingleCondition" resultMap="mapBrand">
        select *
        from tb_brand
        where
        <choose>
            <when test="status != null">
                status = #{status}
            </when>
            <when test="brandName != null and brandName != '' ">
                brand_name like #{brandName}
            </when>
            <when test="companyName != null and companyName != '' ">
                company_name like #{companyName}
            </when>
            <otherwise>
                1 = 1
            </otherwise>
        </choose>
        ;
    </select>

这样写还是有些牵强,这时候<where>标签又派上用场了,它能够判断里面的条件有没有成立的,从来来生成正确的SQL语句

    <select id="selectBySingleCondition" resultMap="mapBrand">
        select *
        from tb_brand
        <where>
            <choose>
                <when test="status != null">
                    status = #{status}
                </when>
                <when test="brandName != null and brandName != '' ">
                    brand_name like #{brandName}
                </when>
                <when test="companyName != null and companyName != '' ">
                    company_name like #{companyName}
                </when>
                <otherwise>
                    1 = 1
                </otherwise>
            </choose>
        </where>
        ;
    </select>

添加数据

当在页面中添加一个商品时,就需要用到插入的功能了

商品的ID应该是不需要我们手动输入的,自增的主键

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

编写测试程序

    @Test
    public void testAdd() throws IOException {
//        假设的参数
        int status = 1;
        String brandName = "蓝翔挖掘机学校";
        String companyName = "山东蓝翔";
        String description = "挖掘技术哪家强,中国山东找蓝翔";
        int orderd = 1999;
//        1.加载mybatis配置文件
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

//        2.获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

//        3.获取对应的mapper
        BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);

//        封装成对象
        Brand brand = new Brand();
        brand.setStatus(status);
        brand.setBrandName(brandName);
        brand.setCompanyName(companyName);
        brand.setDescription(description);
        brand.setOrdered(orderd);

//          4.执行SQL
        mapper.add(brand);
//        4.释放资源
        sqlSession.close();
    }

通过控制台的日志输出,我们知道添加成功了,但是在数据库查询却没有

image-20220923154018767

image-20220923153813083

这是因为MyBatis在执行这条SQL语句时,帮我们开启了事务,当SQL执行完成了,它又进行了事务回滚,就导致没有成功插入,这就需要我们手动提交事务。

可以在执行完成SQL语句后,通过调用方法来提交事务

//          4.执行SQL
        mapper.add(brand);
//        提交事务
        sqlSession.commit();

当然,我们也可以在获得SqlSession对象的时候,设置参数为true,这样就能帮我们自动提交事务

//        2.获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
主键返回

返回添加数据的主键

在数据添加成功后,有时候我们需要获取插入数据的主键,来用于接下来的操作

来看一下,通过该对象来获取id,发现是null

image-20220923155207605

image-20220923155145045

其实我们插入成功后,id值也就有了,但是没有绑定到我们的这个对象身上

可以在SQL语句部分这样写

<!--    useGenerateKeys:获取自动增长的主键值,true表示获取
        keyProperty:指定主键是表的哪一个字段
-->
<insert id="add" useGeneratedKeys="true" keyProperty="id">

    insert into tb_brand(brand_name, company_name, ordered, description, status)
    values (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
</insert>

这样就绑定到了对象身上

image-20220923155639549

修改功能

修改全部字段

写SQL

    <update id="update">
        update tb_brand
        set brand_name   = #{brandName},
            company_name = #{companyName},
            brand_name   = #{brandName},
            description  = #{description},
            status       = #{status}
        where id = #{id};
    </update>

注意 : 提交事务

修改动态字段

当用户需要修改一个字段时,并不需要修改全部字段,这时候就需要做出判断,之前也做过

    <update id="update">
        update tb_brand
        set
        <if test="brandName != null">
            brand_name = #{brandName},
        </if>
        <if test="companyName != null">
            company_name = #{companyName},
        </if>
        <if test="ddescription != null">
            description = #{description},
        </if>
        <if test="status != null">
            status = #{status}
        </if>
        where id = #{id};
    </update>

经过前几次的学习,我们肯定能判断出这个SQL语句是有问题的,因为假如没有一个if条件成立,那么SQL语句就会出错

同样,Mybatis中提供了与<where>标签类似的功能,<set>标签,他能够判断哪些条件成立,哪些条件不成立,做出争取的SQL语句

    <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="description != null and description != ''">
                description = #{description},
            </if>
            <if test="status != null">
                status = #{status}
            </if>
            <if test="ordered != null">
                ordered = #{ordered}
            </if>
        </set>
        where id = #{id};
    </update>

删除功能

删除一个

没啥说的

<delete id="delete">
    delete from tb_brand where id = #{id};
</delete>
批量删除

当用户需要批量删除时,对应的SQL语句就要发生变化了

在实际开发中,批量删除时,我们会将多个参数封装成一个数组,那么在接口中应该这样定义

void deleteByIds(int[] ids);

我们一般需要删除多条数据时,会这样写

delete from tb_brand where id in (?,?,?);

但是我们并不知道这个数组中有几个数据,所以就不知道写多少个占位符。

MyBatis中提供了<foreach>标签来遍历容器

foreach标签

  • collection属性,用来指定遍历的容器名

    注意:MyBatis会将数组参数,封装为一个Map集合

    • 默认: array = 数组
    • 可以在方法定义时,用@Param注解来指定map集合默认的key名称
  • item属性:本次迭代获取的元素名称

  • separator属性:集合迭代之间的分隔符

  • open属性:该属性值是在拼接SQL语句时的符号

  • close属性:拼接结束时的符号

<!--    批量删除-->
<delete id="deleteByIds">
    delete from tb_brand
    where
    id in
    <foreach collection="array" item="id" separator="," open="(" close=")">
        #{id}
    </foreach>
</delete>

image-20220923165741689

这样,当我们有数组中有几个元素,就会动态的生成几个?

参数传递

MyBatis的对接口中的参数以及在对应SQL语句之间参数是如何封装、传递的。

MyBatis接口方法中可以接收各种各样的参数

  • 多个参数
  • 单个参数: 可以是一下类型
    • POJO类型:自定义类
    • Map集合类型
    • Collection集合类型
    • List集合类型
    • Array类型
    • 其他类型
多个参数

当我们的接口方法中定义了多个参数时,MyBatis会将这些参数封装成Map集合对象,值就是参数值,当我们没有使用@Param时,Map中默认的的键是这样的

  • 以arg开头

    第一个参数的键是"arg0",第二个参数的键是"arg1",以此类推

    map.put(“arg0”,参数值1);

    map.put(“arg1”,参数值2);

  • 还有一个键,是以param开头的

    map.put(“param1”,参数值1);

    map.put(“param2”,参数值2);

这两个键都是适用的,可以掩饰一波

这是接口方法

Person select(Integer id, String name);

这是SQL映射文件中 的SQL语句

<select id="select" resultMap="personMap">
    select *
    from user
    where id = #{arg0}
    and name = #{arg1};
</select>

<select id="select" resultMap="personMap">
    select *
    from user
    where id = #{param1}
    and name = #{param2};
</select>

这两种SQL写法 都是可以查询到同样的结果

image-20220923234305395

当我们使用了@Param注解后,MyBatis会将arg替换成注解中的名称,但是param的键还是会存在的

接口方法

Person select(@Param("id") Integer id, String name);

SQL语句

<select id="select" resultMap="personMap">
    select *
    from user
    where id = #{id}
    and name = #{param2};
</select>

不推荐使用Map默认设置的两种键的方式,推荐使用注解参数的方式,因为这样代码的可读性就会变强

单个参数
  • POJO类型,也就是我们自定义的对象类型

    直接使用,只要保证属性名和SQL语句的参数占位符名称一致即可

  • Map集合类型

    直接使用,只要Map集合中的键与SQL语句的参数占位符名称一致即可

  • 其他类型

    直接使用,比如说,String , Integer等常用的类型

接下来的这几个对象就有些特殊了😄

  • Collection集合类型

    MyBatis会将此类对象封装到map集合中

    map.put("arg0",collection对象);
    map.put("collection",collection对象);
    
  • List集合类型

    也会封装到Map集合中

    map.put("arg0",list对象);
    map.put("collection",list集合);
    map.put("list",list集合);
    
  • Array类型

    照样封装到Map集合中

    map.put("arg0",数组);
    map.put("array",数组);
    

只需要记住,用注解@Param来即可,书写起来更方便,代码的可读性更强

注解开发

使用配置文件和注解开发的本质是一样的,但是使用注解会更加方便

@Select("select * from user where id = #{id}")
Person select(int id);

针对不同类型的SQL语句,MyBatis提供了四种注解

  • 查询:@Select
  • 添加:@Insert
  • 修改:@Update
  • 删除:@Delete

使用注解来完成简单的SQL语句,使用SQL配置文件来完成复杂的SQL语句

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值