MaBatis

1.1 Mybatis概述

1.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

持久层框架的使用占比:

持久层

负责将数据到保存到数据库的那一层代码。 以后开发我们会将操作数据库的 Java 代码作为持久层。而 Mybatis 就是对 jdbc 代码进行了封装。 

框架

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

1.1.2 JDBC 缺点

下面是 JDBC 代码,我们通过该代码分析都存在什么缺点:

1.存在硬编码 

  • 注册驱动、获取连接:上图标1的代码有很多字符串,而这些是连接数据库的四个基本信息,以后如果要将 Mysql 数据库换成其他的关系型数据库的话,这四个地方都需要修改,如果放在此处就意味着要修改我们的源代码。 

  • SQL语句:上图标 2 的代码。如果表结构发生变化,SQL语句就要进行更改。这也不方便后期的维护。 

2.操作繁琐 

  • 需要手动设置参数:上图标 3 的代码需要为 SQL 语句手动设置参数。

  • 需要手动封装结果集 :上图标 4 的代码是对查询到的数据进行封装,而这部分代码是没有什么技术含量,而且特别耗费时间

1.1.3 使用 MyBatis 进行优化

  • 硬编码可以配置到配置文件 

  • 操作繁琐的地方mybatis都自动完成

如下图所示:

1.2 MyBatis使用步骤

这里,我们借助一个需求来进行 MyBatis 的快速入门。

需求:查询user表中所有的数据

步骤:具体步骤如下所示

第一步:在数据库中创建一个 user 表,添加数据

第二步:创建模块,导入相关坐标

在这一步中别忘了在 resource 目录下添加 logback 的配置文件 logback.xml

第三步:编写 MyBatis 核心配置文件

通过核心配置文件替换连接信息解决硬编码问题,在 resources 目录下创建 mybatis 的配置文件 mybatis-config.xml ,内容如下:

第四步:编写 SQL 映射文件

统一管理 sql 语句,解决硬编码问题。在 resources 目录下创建映射配置文件 UserMapper.xml ,内容如下:

第五步:编码

在 com.itheima.pojo 包下创建 User类

在 com.itheima 包下编写 MybatisDemo 测试类

1.3 Mapper代理开发

1.3.1 Mapper代理开发概述

MyBatis基本使用方式的问题:快速入门里写的代码是 MyBatis 的基本使用方式,它也存在硬编码的问题,如下:

这里调用 selectList() 方法传递的参数是映射配置文件中的 namespace.id 值。这样写也不便于后期的维护。如果使用如下图所示的 Mapper 代理方式则不存在硬编码问题。

Mapper代理的好处

  • 解决原生方式中的硬编码 

  • 简化后期执行 SQL

1.3.2 使用Mapper代理要求

使用Mapper代理方式,必须满足以下要求:

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

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

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

1.4 核心配置文件

<?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>
    <!--类型别名,简化sql映射文件中resultType属性值的编写-->
    <typeAliases>
        <typeAlias alias="User" type="com.example.User"/><!--单个类型别名的配置-->
        <package name="com.example.model"/><!-- 批量配置多个类型别名 -->
    </typeAliases>
    <!--mybatis的全局配置-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/><!--日志设置为MyBatis提供的标准日志-->
    </settings>
    <!--多环境配置,default表示默认使用的环境-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/> <!--设置为JDBC的事务管理器,默认开启事务但不自动提交-->
            <dataSource type="POOLED">
                <!--数据库连接信息-->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/使用的数据库名"/>
                <property name="username" value="用户名"/>
                <property name="password" value="用户名对应的密码"/>
            </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://localhost:3306/使用的数据库名"/>
                <property name="username" value="用户名"/>
                <property name="password" value="用户名对应的密码"/>
            </dataSource>
        </environment>
    </environments>
    <!--映射文件位置-->
    <mappers>
        <mapper resource="com/example/mapper/UserMapper.xml"/><!--扫描指定的sql映射⽂件-->
        <package name="com.example.mapper"/><!--扫描包下的所有sql映射⽂件-->
    </mappers>
</configuration>

1.5 映射文件

<?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.example.dao.UserMapper">
    <!-- 查询结果映射 -->
    <resultMap id="userResultMap" type="User">
        <id property="id" column="user_id" />
        <result property="username" column="user_name"/>
        <result property="password" column="hashed_password"/>
    </resultMap> 

    <!-- 查询操作 -->
    <select id="getUserById" parameterType="int" resultType="userResultMap">
        SELECT * FROM users WHERE id = #{id}
    </select>

    <!-- 插入操作 -->
    <insert id="insertUser">
        INSERT INTO users (username, password, email) VALUES (#{username}, #{password}, #{email})
    </insert>

    <!-- 更新操作 -->
    <update id="updateUser">
        UPDATE users SET username = #{username}, password = #{password}, email = #{email} WHERE id = #{id}
    </update>

    <!-- 删除操作 -->
    <delete id="deleteUser">
        DELETE FROM users WHERE id = #{id}
    </delete>
</mapper>

1.5.1 参数占位符

参数占位符是指在SQL语句里使用的占位符,用来表示需要动态插入的参数值。mybatis提供了两种参数占位符,分别是#{}、${},开发中建议使用 #{} ,不要使用 ${}。

  • ${} :在处理 ${} 时,是把SQL中的 ${} 直接替换成变量值,然后发送给MySQL服务器执行。

  • #{} :在处理 #{} 时,首先会将SQL中的 #{} 替换为占位符 ?,接着进行预编译,然后调用PreparedStatment的set方法,这个set方法能够对参数值中的敏感字符进行转义,防止SQL注入,并能将转义后的参数值发送给MySQL,绑定到占位符上。

1.5.2 parameterType

对于有参数的 mapper 接口方法,我们在映射配置文件中应该配置 parameterType 来指定参数类型。但是该属性可以省略。

<select id="selectById" parameterType="int" resultMap="brandResultMap">
    select *
    from tb_brand where id = ${id};
</select>

1.5.3 SQL语句的特殊字段

以后肯定会在SQL语句中写一下特殊字符,比如某一个字段大于某个值,如下图

可以看出报错了,因为映射配置文件是 xml 类型的问题,而 > < 等这些字符在 xml 中有特殊含义,所以此时我们需要将这些符号进行转义,可以使用以下两种方式进行转义

  • 转义字符:下图的 &lt; 就是 < 的转义字符。

  • 使用 <![CDATA[内容]]>

1.5.4 动态拼接SQL

1.<if> 标签

<if> 标签允许根据条件动态包含 SQL 片段,在 test 属性中定义条件。

<select id="getUserById" parameterType="int" resultType="com.example.model.User">
      SELECT * FROM users
      WHERE id = #{id}
      <if test="username != null">
          AND username = #{username}
      </if>
</select>

2.<where> 标签

<where> 标签用于拼接 WHERE 子句,它会自动去除不必要的 AND 或 OR。另外,使用where标签时,需要给每个条件前都加上 and 关键字。

<select id="getUsersByCriteria" parameterType="map" resultType="com.example.model.User">
      SELECT * FROM users
      <where>
        <if test="username != null">
          AND username = #{username}
        </if>
        <if test="email != null">
          AND email = #{email}
        </if>
      </where>
</select>

3. <set> 标签

<set> 标签用于拼接 UPDATE 语句的 SET 子句。

<update id="updateUser" parameterType="com.example.model.User">
      UPDATE users
      <set>
        <if test="username != null">username = #{username},</if>
        <if test="password != null">password = #{password},</if>
        <if test="email != null">email = #{email},</if>
      </set>
      WHERE id = #{id}
</update>

4.<foreach> 标签

<foreach> 标签用于迭代集合元素,动态生成多个 SQL 片段。

  • collection 属性:mybatis 会将数组参数,封装为一个Map集合。默认:array = 数组;使用@Param注解改变map集合的默认key的名称

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

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

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

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

<select id="getUsersByIdList" parameterType="java.util.List" resultType="com.example.model.User">
      SELECT * FROM users
      WHERE id IN
      <foreach item="item" index="index" collection="idList" open="(" separator="," close=")">
        #{item}
      </foreach>
</select>

5.<sql>、<include>标签

<sql> 标签用于定义可重用的 SQL 片段,可以在多个 SQL 语句中引用。<include>标签用于在SQL语句中引用SQL片段。

<!-- 定义一个可重用的 SQL 片段 -->
<sql id="userColumns">
    id, username, password, email
</sql>

<!-- 在 SELECT 语句中引用该 SQL 片段 -->
<select id="getUsers" resultType="com.example.model.User">
    SELECT 
    <include refid="userColumns"/>
    FROM users
</select>

6.<choose>、<when>、<otherwise>标签
<choose> 标签类似于 Java 中的 switch 语句,允许在多个选项中选择一个执行。每个 <when> 标签表示一个选项,最后的 <otherwise> 标签用于指定默认情况。

<select id="getUserByCriteria" parameterType="com.example.model.User" resultType="com.example.model.User">
     SELECT * FROM users
     <where>
         <choose>
             <when test="id != null">
                 AND id = #{id}
             </when>
             <when test="username != null">
                 AND username = #{username}
             </when>
             <otherwise>
                 AND 1=1 <!-- 默认情况,可以省略 -->
             </otherwise>
         </choose>
     </where>
</select>

2.10 Mybatis 参数传递

Mybatis 接口方法中可以接收各种各样的参数,如下:

多个参数:以后接口参数是多个时,在每个参数上都使用 @Param 注解。这样代码的可读性更高。

单个参数:单个参数又可以是如下类型

  • POJO 类型

  • Map 集合类型

  • Collection 集合类型

  • List 集合类型

  • Array 类型

  • 其他类型

2.10.1 多个参数

如下面的代码,就是接收两个参数,而接收多个参数需要使用 @param 注解,那么为什么要加该注解呢?

User select(@Param("username") String username,@Param("password") String password);
<select id="select" resultType="user">
    select *
    from tb_user
    where 
        username=#{username}
        and password=#{password}
</select>

上面这个问题要弄明白就必须来研究 Mybatis 底层对于这些参数是如何处理的。

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

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

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

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

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

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

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

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

2.10.2 单个参数

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

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

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

  • map.put("arg0",collection集合);

  • map.put("collection",collection集合);

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

  • map.put("arg0",list集合);

  • map.put("collection",list集合);

  • map.put("list",list集合);

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

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

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

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

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

2.11 Mapper注解

使用代码获取代理对象:在MyBatis中,利用编程式进行数据查询,主要就是下面几行代码。

//获取SqlSession对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
//获取Mapper代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
//利用代理对象实现增删改查
List<LwUser> userList = userMapper.listUserByUserName("孤狼1号");

使用@Mapper注解获取代理对象:上述获取 Mapper 接口的代理对象非常麻烦,我们在引入 Mybatis 和 Spring 整合的 jar 包后,可以将 Mybatis 提供的 @Mapper 注解放到 Mapper 接口的上面,将代理对象注册为 Spring 的 Bean,在使用的时候,直接从 IOC 容器中取即可。另外,不要忘了添加 @MapperScan 注解对 @Mapper 注解进行扫描。

@Mapper
public interface UserMapper extends BaseMapper<User> {
    @Select("select * from tb_user")
    List<User> getAll();
}

2.12 注解实现

上述都是在映射文件中编写SQL语句,我们可以使用注解替换映射文件中的SQL语句。通常,注解和配置文件可以搭配起来使用,注解完成简单功能,配置文件完成复杂功能。我们之前写的动态 SQL 就是复杂的功能。如下就是使用注解进行开发:

@Repository("userMapper")
public interface UserMapper {
    // 插入用户
    @Insert("INSERT INTO users (name, email) VALUES ({0}, {1})")
    void addUser(@Param("name") String name, @Param("email") String email);

    // 查询所有用户
    @Select("SELECT * FROM users")
    List<User> getAllUsers();

    // 更新用户信息
    @Update("UPDATE users SET name = #{name}, email = #{email} WHERE id = #{id}")
    void updateUser(@Param("id") Long id, @Param("name") String name, @Param("email") String email);

    // 删除用户
    @Delete("DELETE FROM users WHERE id = #{id}")
    void deleteUser(@Param("id") Long id);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

真滴book理喻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值