MyBatis笔记

MyBatis

1.1 简介

什么是MyBatis?

  • MyBatis是一款优秀的持久层框架,用于简化JDBC开发
  • MyBatis本是Apache的一个开源项目iBatis,2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis。2013年11月迁移到Github
  • 官网:https://mybatis.org/mybatis-3/zh/index.html

持久层:

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

持久层的含义:就是将数据进行持久化的一层(存进数据库就长久保存,所以持久)

框架:

  • 框架就是一个半成品软件,是一套可重用的、通用的、软件基础代码模型
  • 在框架的基础上构建软件编写更加高效、规范、通用、可扩展

JDBC的缺点 ---> MyBatis的优点:

  1. 硬编码 ---> MyBatis使用配置文件

    • 注册驱动,获取链接

    • SQL语句

  2. 操作繁琐 ---> MyBatis自动完成

    • 手动设置参数
    • 手动封装结果集

image-20220927160354549

1.2 快速入门

例:查询user表中的信息

  1. 创建user表,添加数据

image-20220927160545815

  1. 创建模板,导入坐标

    <!-- MyBatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.6</version>
    </dependency>
    
    <!-- MySQL驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.29</version>
    </dependency>
    
  2. 编写MyBatis核心配置文件 --> 替换连接信息,解决硬编码问题

    • 创建mybatis-config.xml文件位于resources文件夹下

    • 编写mybatis-config.xml配置信息,可在官网获取

      <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE configuration
      PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
      "https://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://localhost:3306/test?useSSL=false&amp;allowPublicKeyRetrieval=true&amp;serverTimezone=UTC"/>
              <property name="username" value="${username}"/> <!--数据库用户名--> 
              <property name="password" value="${password}"/> <!--密码--> 
            </dataSource>
          </environment>
        </environments>
          
        <mappers>
           <!-- 加载sql映射文件 -->
          <mapper resource="User.xml"/>
        </mappers>
      </configuration>
      
  3. 编写SQL映射文件 --> 统一管理sql语句,解决硬编码问题

    • 在resources文件夹下创建UserMapper.xml文件

    • 编写UserMapper.xml

      <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE mapper
              PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
              "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
      
      <!--
          namespace:名称空间
      -->
      <mapper namespace="test">
          <select id="selectAll" resultType="com.hqa.pojo.User">
              select * from user
          </select>
      </mapper>
      
  4. 编码

    • 定义POJO类(pojo文件夹中创建User的JavaBean类)
     //1.加载mybatis的核心配置文件,获取SqlSessionFactory
    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
    List<User> users = sqlSession.selectList("test.selectAll");
    
    System.out.println(users);
    
    //4.释放资源
    sqlSession.close();
    

1.3 Mapper 代理开发

使用Mapper代理开发的目的:

  • 解决原生方式中的硬编码
  • 简化后期执行SQL

image-20220927162322955

同上一章的例子:

  1. 定义与SQL映射文件同名的Mapper接口,并且将Mapper接口和SQL映射文件放置在同一目录下

    image-20220927163815393

    因为resource目录在编译后就和java文件一样都存在classes目录下,所以只需在resource目录下创建和Mapper接口的目录结构相同的文件夹即可

  2. 设置SQL映射文件的namespace属性为Mapper接口为全限定名

    image-20220927163540405

  3. 在Mapper接口中定义方法,方法名就是SQL映射文件中sql语句的id,并保持参数类型和返回值类型一致

    public interface UserMapper {
        List<User> selectAll(); //返回值为一个Userd对象集合
    }
    
  4. 编码

    • 通过SqlSession的getMapper方法获取Mapper接口的代理对象

      UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
      
    • 调用对应方法完成sql的执行

      List<User> users =  userMapper.selectAll();
      
      System.out.println(users);
      

image-20220927165411629

1.4 MyBatis 核心配置文件

MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:

配置各个标签时,需要遵守以上列表的前后顺序

常用配置:

  • 类型别名

    <typeAliases>
      <package name="domain.blog"/> <!--包名-->
    </typeAliases>
    

    这样可以省略映射文件中返回类型的缩写

    <!--原来的-->
    <select id="selectAll" resultType="com.hqa.pojo.User">
        select * from user
    </select>
    
    <!--使用别名-->
    <select id="selectAll" resultType="user">
        select * from user
    </select>
    

1.5 字段映射

查询结果NULL,出现这个问题一般是数据库字段名与实体类名不相符,使用resultMap字段映射可解决这个问题

image-20220928155053737

resultMap中标签有两种类型:

  • id:完成主键字段的映射
    • column:表的列名
    • property:实体类的属性名
  • result:完成一般字段的映射
    • column:表的列名
    • property:实体类的属性名

1.6 MyBatis 细节

1.6.1 占位符

MyBatis的参数占位符有两种:

  • #{}:会将其替换为 ? ,为了防止SQL注入。(一般用这个)
  • ${}:拼接sql,会存在SQL注入问题
  • 使用时机:
    • 参数传递时,用#{}
    • 表名或者列名不固定的情况下,用${}

image-20220928161557725

1.6.2 特殊字符处理

  • 转义符

    例: < 的转义字符为 &lt;

    image-20220928162046336

  • CDATA区

    例: <![CDATA[内容]]>

    IDEA中打CD后即可自动补全

    image-20220928162254171

1.6.3 参数传递方式

mybatis参数的传递有三种方式:

  • 散装参数
    • 需要使用@Param("SQL中的参数占位符名称")
  • 对象参数
    • 只需要保证SQL中的参数名和实体类属性名对应上,即可设置成功
  • map集合参数
    • 只需要保证SQL中的参数名和map集合的键的名称对应上,即可设置成功

image-20220928164707339

1.6.4 主键返回

在添加数据成功后,需要获取插入数据库数据的主键的值,这时候就需要使用主键返回

开启主键返回方法:

在insert标签里添加useGeneratedKeys="true"和keyProperty="id"在两个属性

<!--  插入数据  -->
<insert id="addAll" useGeneratedKeys="true" keyProperty="id">
    insert into tb_brand(brand_name, company_name, ordered, description, status)
    value (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
</insert>

1.7 动态SQL

SQL语句会随用户的输入或外部条件的变化而变化,我们称为动态SQL

  • MyBatis对动态sql有很强大的支撑

    • if

    • choose (when, otherwise)

    • trim (where, set)

    • foreach

1.7.1 动态条件查询

<!--  条件查询  -->
<select id="selectByCondition" resultMap="BrandResultMap">
    select * from tb_brand
    where status like #{status}
    and company_name like #{companyName}
    and brand_name like #{brandName}
</select>

<!--  动态条件查询 where -->
<select id="selectByCondition" resultMap="BrandResultMap">
    select * from tb_brand
    <where>
        <if test="status != null">
            and status like #{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>

<!--  动态条件查询 choose  -->
<select id="selectByCondition" resultMap="BrandResultMap">
    select * from tb_brand
    <where>
        <choose>
            <when test="status != null">
                and status like #{status}
            </when>
            <when test="companyName != null and companyName != ''">
                and company_name like #{companyName}
            </when>
            <when test="brandName != null and brandName != ''">
                and brand_name like #{brandName}
            </when>
            <otherwise>
                1 = 1
            </otherwise>
        </choose>
    </where>
</select>

1.7.2 动态修改字段

<!--  修改数据  -->
<update id="updateAll">
    update tb_brand
    set brand_name = #{brandName},
    company_name = #{companyName},
    ordered = #{ordered},
    description = #{description},
    status = #{status}
    where
    id = #{id}
</update>

<!--
	使用上面的修改数据,如果用户只修改其中一条数据,那么其他数据可能会跟着被修改,所以使用动态修改会更加安全
-->

<!--  动态修改数据  -->
<update id="updateAll">
    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">
            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.7.2 批量删除数据

mapper:

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

@Param 注解修改key名

<!--  删除单条数据  -->
<delete id="deleteById">
    delete from tb_brand where id = #{id}
</delete>

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

foreach标签中:separator 分隔符 open 起始符 open 结束符

1.8 MyBatis 参数传递

MyBatis 接口方法中可以接收各种各样的参数,MyBatis 底层对于这些参数进行不同的封装处理方式

  • 单个参数

    • POJO类型:直接使用,实体类属性名和参数占位符名称一致

    • Map类型:直接使用,键名和参数占位符名称一致

    • Collection:封装为Map集合

      map.put("collection", collection集合);
      map.put("agr0", collection集合);
      
    • List:封装为Map集合

      map.put("collection", list集合);
      map.put("list", list集合);
      map.put("arg0", list集合);
      
    • Array:封装为Map集合

      map.put("array", 数组);
      map.put("arg0", 数组);
      
    • 其他类型:直接使用

    • 多个参数:封装为Map集合

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

    将来都用@Param注解来修改Map集合中默认的键名,并使用修改后的名称来取值,这样可读性更高,如:

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

1.9 注解开发

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

如:

package org.mybatis.example;
public interface BlogMapper {
  @Select("SELECT * FROM blog WHERE id = #{id}")
  Blog selectBlog(int id);
}

使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心,还会让本就复杂的 SQL 语句更加混乱不堪。 因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句。

也就是注解完成简单功能,配置文件完成复杂功能

posted @   可乐加冰q_q  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示