MyBatis详解

引言

MyBatis 是一个优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

在学习MySQL数据库时,都是利用图形化客户端工具(如:idea、datagrip),来操作数据库的。

在客户端工具中,编写增删改查的SQL语句,发给MySQL数据库管理系统,由数据库管理系统执行SQL语句并返回执行结果。
增删改操作:返回受影响行数
查询操作:返回结果集(查询的结果)

做为后端程序开发人员,通常会使用Java程序来完成对数据库的操作。Java程序操作数据库,现在主流的方式是:Mybatis。

1. 什么是MyBatis

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

在这里插入图片描述

2. JDBC介绍

虽然说通过Mybatis可以很方便的进行数据库的访问操作。但是大家要明白,其实java语言操作数据库呢,只能通过一种方式:使用sun公司提供的 JDBC 规范。而Mybatis框架,就是对原始的JDBC程序的封装。

2.1 介绍

JDBC: ( Java DataBase Connectivity ),就是使用Java语言操作关系型数据库的一套API。用于连接和执行查询以访问不同类型的数据库。JDBC 提供了一个标准库,用于建立数据库连接、执行 SQL 语句以及处理查询结果。它作为 Java 应用程序和各种关系数据库之间的桥梁,使得数据库操作可以在 Java 中以一种平台无关的方式进行。
在这里插入图片描述

2.1.1 主要组件

  • 驱动程序(Driver): 数据库厂商提供的 JDBC 驱动允许 Java 应用程序与数据库建立连接。
  • Connection: 一旦驱动程序加载,程序员可以利用 Connection 对象与数据库建立连接。
  • Statement: Statement 对象用于执行 SQL 命令。
  • ResultSet: 执行查询后,结果保存在 ResultSet 对象中。

2.1.2 基本流程

  1. 加载数据库驱动
  2. 建立到数据库的连接
  3. 创建一个 StatementPreparedStatement 对象
  4. 执行 SQL 查询或更新
  5. 处理结果(如果有)
  6. 关闭连接和释放资源

2.1.3 示例代码

以下是使用 JDBC 连接 MySQL 数据库的 Java 示例代码:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class JdbcExample {
    public static void main(String[] args) {
        try {
            // 第一步:加载驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            
            // 第二步:建立数据库连接
            Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testDB", "用户名", "密码");
            
            // 第三步:创建 Statement 对象
            Statement stmt = conn.createStatement();
            
            // 第四步:执行 SQL 查询
            ResultSet rs = stmt.executeQuery("SELECT * FROM employees");
            
            // 第五步:处理查询结果
            while (rs.next()) {
                System.out.println(rs.getString("name") + ", " + rs.getInt("age"));
            }
            
            // 第六步:关闭资源
            rs.close();
            stmt.close();
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

DriverManager(类):数据库驱动管理类。

  • 作用:
  1. 注册驱动
  2. 创建java代码和数据库之间的连接,即获取Connection对象

Connection(接口):建立数据库连接的对象

  • 作用:用于建立java程序和数据库之间的连接

Statement(接口): 数据库操作对象(执行SQL语句的对象)。

  • 作用:用于向数据库发送sql语句

ResultSet(接口):结果集对象(一张虚拟表)

  • 作用:sql查询语句的执行结果会封装在ResultSet中

通过上述代码,我们看到直接基于JDBC程序来操作数据库,代码实现非常繁琐,所以在项目开发中,我们很少使用。 在项目开发中,通常会使用Mybatis这类的高级技术来操作数据库,从而简化数据库操作、提高开发效率。

2.1.4 问题分析

原始的JDBC程序,存在以下几点问题:

  1. 数据库链接的四要素(驱动、链接、用户名、密码)全部硬编码在java代码中
  2. 查询结果的解析及封装非常繁琐
  3. 每一次查询数据库都需要获取连接,操作完毕后释放连接, 资源浪费, 性能降低

2.1.5 技术对比

分析在mybatis中,是如何解决这些问题的:

  1. 数据库连接四要素(驱动、链接、用户名、密码),都配置在springboot默认的配置文件 application.properties中
  2. 查询结果的解析及封装,由mybatis自动完成映射封装,我们无需关注
  3. 在mybatis中使用了数据库连接池技术,从而避免了频繁的创建连接、销毁连接而带来的资源浪费。

而对于Mybatis来说,我们在开发持久层程序操作数据库时,需要重点关注以下两个方面:

  1. application.properties
#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=1234
  1. Mapper接口(编写SQL语句)
@Mapper
public interface UserMapper {
    @Select("select id, name, age, gender, phone from user")
    public List<User> list();
}

3. 数据库连接池

3.1 介绍

数据库连接池是个容器,负责分配、管理数据库连接(Connection)

没有使用数据库连接池:

  • 客户端执行SQL语句:要先创建一个新的连接对象,然后执行SQL语句,SQL语句执行后又需要关闭连接对象从而释放资源,每次执行SQL时都需要创建连接、销毁链接,这种频繁的重复创建销毁的过程是比较耗费计算机的性能。

使用了数据库连接池
在这里插入图片描述

  • 程序在启动时,会在数据库连接池(容器)中,创建一定数量的Connection对象
    允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个
  • 客户端在执行SQL时,先从连接池中获取一个Connection对象,然后在执行SQL语句,SQL语句执行完之后,释放Connection时就会把Connection对象归还给连接池(Connection对象可以复用)释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引起的数据库连接遗漏
  • 客户端获取到Connection对象了,但是Connection对象并没有去访问数据库(处于空闲),数据库连接池发现Connection对象的空闲时间 > 连接池中预设的最大空闲时间,此时数据库连接池就会自动释放掉这个连接对象

3.2 常用数据库连接池

  • C3P0
  • Druid(德鲁伊)
  • Hikari(追光者) [默认的连接池]

3.3 使用示例(Hikari)

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

public class HikariCPExample {
    public static void main(String[] args) {
        // 配置 HikariCP
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://localhost:3306/testDB");
        config.setUsername("用户名");
        config.setPassword("密码");

        // 创建连接池
        HikariDataSource ds = new HikariDataSource(config);

        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        
        try {
            // 从连接池中获取连接
            conn = ds.getConnection();

            // 创建 Statement 对象
            stmt = conn.createStatement();

            // 执行 SQL 查询
            rs = stmt.executeQuery("SELECT * FROM employees");

            // 处理查询结果
            while (rs.next()) {
                System.out.println(rs.getString("name") + ", " + rs.getInt("age"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 释放资源
            try {
                if (rs != null) rs.close();
                if (stmt != null) stmt.close();
                if (conn != null) conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        // 关闭连接池
        ds.close();
    }
}

4. Lombok

4.1 定义和目的

Lombok 是一个 Java 库,旨在通过注解(Annotations)减少 Java 代码的样板代码(Boilerplate Code)。Lombok 可以帮助开发者自动生成诸如 getter、setter、equals、hashCode 和 toString 方法等常用代码。这样不仅减少了代码量,还提高了代码的可读性和维护性。

4.2 常用注解

注解作用
@Getter/@Setter为所有的属性提供get/set方法
@ToString会给类自动生成易阅读的 toString 方法
@EqualsAndHashCode根据类所拥有的非静态字段自动重写 equals 方法和 hashCode 方法
@Data提供了更综合的生成代码功能(@Getter + @Setter + @ToString + @EqualsAndHashCode)
@NoArgsConstructor为实体类生成无参的构造器方法
@AllArgsConstructor为实体类生成除了static修饰的字段之外带有各参数的构造器方法

4.3 使用

第1步:在pom.xml文件中引入依赖

<!-- 在springboot的父工程中,已经集成了lombok并指定了版本号,故当前引入依赖时不需要指定version -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

第2步:在实体类上添加注解

import lombok.Data;

@Data
public class User {
    private Integer id;
    private String name;
    private Short age;
    private Short gender;
    private String phone;
}

在实体类上添加了@Data注解,那么这个类在编译时期,就会生成getter/setter、equals、hashcode、toString等方法。
在这里插入图片描述

说明:@Data注解中不包含全参构造方法,通常在实体类上,还会添加上:全参构造、无参构造

import lombok.Data;

@Data //getter方法、setter方法、toString方法、hashCode方法、equals方法
@NoArgsConstructor //无参构造
@AllArgsConstructor//全参构造
public class User {
    private Integer id;
    private String name;
    private Short age;
    private Short gender;
    private String phone;
}

Lombok的注意事项:

  • Lombok会在编译时,会自动生成对应的java代码
  • 在使用lombok时,还需要安装一个lombok的插件(新版本的IDEA中自带)

在这里插入图片描述

5. Mybatis基础操作

MyBatis 是一个开源的 SQL 映射框架,它允许你直接使用 SQL 语句,而不需要像 JPA 那样使用 HQL 或 JPQL。MyBatis 可以与 Java 对象模型 (POJOs) 直接映射 SQL 数据库记录,为开发者提供更多的灵活性。

5.1 查询

查询是数据库交互中非常常见的一种操作。在 MyBatis 中,我们可以通过多种方式来进行查询。

5.1.1 根据主键 ID 查询

XML 配置
在 XML 映射文件中,你可以像下面这样定义一个根据 ID 查询的 SQL 语句:

<select id="getEmployeeById" parameterType="int" resultType="com.example.Employee">
  SELECT * FROM employee WHERE id = #{id}
</select>

Java 代码
在 Java 代码中,你可以这样使用:

try (SqlSession session = sqlSessionFactory.openSession()) {
  EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
  Employee employee = mapper.getEmployeeById(1);
  System.out.println(employee);
}

5.1.2 条件查询

XML 配置
条件查询通常更复杂,但也可以通过 MyBatis 的 XML 配置来实现:

<select id="findEmployees" resultType="com.example.Employee">
  SELECT * FROM employee
  <where>
    <if test="name != null">
      name = #{name}
    </if>
    <if test="age != null">
      AND age = #{age}
    </if>
  </where>
</select>

Java 代码

try (SqlSession session = sqlSessionFactory.openSession()) {
  EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
  List<Employee> employees = mapper.findEmployees("John", 30);
  for (Employee employee : employees) {
    System.out.println(employee);
  }
}

5.2 新增

XML 配置

<insert id="insertEmployee" parameterType="com.example.Employee">
  INSERT INTO employee (name, age) VALUES (#{name}, #{age})
</insert>

Java 代码

try (SqlSession session = sqlSessionFactory.openSession()) {
  EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
  Employee newEmployee = new Employee("John", 30);
  mapper.insertEmployee(newEmployee);
  session.commit();
}

5.3 更新

XML 配置

<update id="updateEmployee" parameterType="com.example.Employee">
  UPDATE employee SET name = #{name}, age = #{age} WHERE id = #{id}
</update>

Java 代码

try (SqlSession session = sqlSessionFactory.openSession()) {
  EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
  Employee existingEmployee = new Employee(1, "Jane", 25);
  mapper.updateEmployee(existingEmployee);
  session.commit();
}

5.4 删除

删除操作通常需要小心进行,以避免误删数据。

5.4.1 根据主键 ID 删除

XML 配置

<delete id="deleteById" parameterType="int">
  DELETE FROM employee WHERE id = #{id}
</delete>

Java 代码

try (SqlSession session = sqlSessionFactory.openSession()) {
  EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
  mapper.deleteById(1);
  session.commit();
}

5.4.2 根据主键 ID 批量删除

XML 配置

<delete id="deleteByIds" parameterType="list">
  DELETE FROM employee WHERE id IN
  <foreach item="item" index="index" collection="list" open="(" separator="," close=")">
    #{item}
  </foreach>
</delete>

Java 代码

try (SqlSession session = sqlSessionFactory.openSession()) {
  EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
  List<Integer> ids = Arrays.asList(1, 2, 3);
  mapper.deleteByIds(ids);
  session.commit();
}

6. Mybatis的XML配置文件

6.1 XML配置文件规范

使用Mybatis的注解方式,主要是来完成一些简单的增删改查功能。如果需要实现复杂的SQL功能,建议使用XML来配置映射语句,也就是将SQL语句写在XML配置文件中。

在Mybatis中使用XML映射文件方式开发,需要符合一定的规范:

  1. XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)
  2. XML映射文件的namespace属性为Mapper接口全限定名一致
  3. XML映射文件中sql语句的id与Mapper接口中的方法名一致,并保持返回类型一致。

在这里插入图片描述

<select>标签:就是用于编写select查询语句的。

  • resultType属性,指的是查询返回的单条记录所封装的类型。

6.2 XML配置文件实现

第1步:创建XML映射文件
在这里插入图片描述
在这里插入图片描述

第2步:编写XML映射文件

xml映射文件中的dtd约束,直接从mybatis官网复制即可

<?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">
<mapper namespace="">
 
</mapper>

配置:XML映射文件的namespace属性为Mapper接口全限定名
在这里插入图片描述

<?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">
<mapper namespace="com.itheima.mapper.EmpMapper">

</mapper>

配置:XML映射文件中sql语句的id与Mapper接口中的方法名一致,并保持返回类型一致
在这里插入图片描述

<?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">
<mapper namespace="com.itheima.mapper.EmpMapper">

    <!--查询操作-->
    <select id="list" resultType="com.itheima.pojo.Emp">
        select * from emp
        where name like concat('%',#{name},'%')
              and gender = #{gender}
              and entrydate between #{begin} and #{end}
        order by update_time desc
    </select>
</mapper>

6.3 MybatisX的使用

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

MybatisX的安装:
在这里插入图片描述

可以通过MybatisX快速定位:
在这里插入图片描述

7. Mybatis动态SQL

动态 SQL 是 MyBatis 非常强大的一个特性,它允许你在 SQL 语句中使用动态元素,从而实现更灵活的 SQL 查询。

7.1 动态 SQL - if 元素

在 MyBatis 中,if 元素是用于构造条件 SQL 语句的一种常用动态 SQL 元素。通过使用 if 元素,你可以根据特定条件来动态地添加或修改 SQL 语句,这样可以使得你的 SQL 语句更加灵活和可维护。

7.1.1 基本用法

if 元素允许你根据条件来决定是否需要添加某个 SQL 片段。

XML 配置示例
以下面这个用于搜索员工的 SQL 语句为例:

<select id="findEmployees" resultType="com.example.Employee">
  SELECT * FROM employee
  <where>
    <!-- 如果 name 不为 null,则添加 "AND name = #{name}" 这个条件 -->
    <if test="name != null">
      AND name = #{name}
    </if>
    <!-- 如果 age 不为 null,则添加 "AND age = #{age}" 这个条件 -->
    <if test="age != null">
      AND age = #{age}
    </if>
  </where>
</select>

Java 代码示例

Map<String, Object> params = new HashMap<>();
params.put("name", "John");
params.put("age", null);

try (SqlSession session = sqlSessionFactory.openSession()) {
    EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
    List<Employee> employees = mapper.findEmployees(params);
    for (Employee employee : employees) {
        System.out.println(employee);
    }
}

在这个例子中,如果 name 和 age 都不为 null,则生成的 SQL 语句会同时包括这两个条件。如果其中任何一个为 null,对应的条件则不会被包括在内。

7.1.2 高级用法

也可以将多个 if 元素组合在一起,以构造更复杂的动态 SQL。

XML 配置示例

<select id="findEmployees" resultType="com.example.Employee">
  SELECT * FROM employee
  <where>
    <if test="name != null and name != ''">
      AND name = #{name}
    </if>
    <if test="age != null and age >= 18">
      AND age = #{age}
    </if>
    <if test="department != null">
      AND department = #{department}
    </if>
  </where>
</select>

这里,我们添加了更多的 if 条件,并且每个条件都更加详细。例如,对于 age,除了判断是否为 null,还额外判断了其是否大于或等于 18。

7.2 动态SQL-foreach

在 MyBatis 中,foreach 是一个非常有用的动态 SQL 元素,用于迭代一个集合,并在每一次迭代中都执行某种操作。这个元素特别适用于执行 IN 查询或批量操作。

7.2.1 基本用法

foreach 元素主要用于生成 SQL 语句中的 IN 子句。

XML 配置示例
假设我们有一个需求:根据一组员工 ID 查找所有符合条件的员工记录。

<select id="findEmployeesByIds" resultType="com.example.Employee">
  SELECT * FROM employee WHERE id IN
  <foreach item="id" index="index" collection="ids" open="(" separator="," close=")">
    #{id}
  </foreach>
</select>

在这个例子中,foreach 元素会遍历名为 ids 的集合,并将集合中的每一个元素插入到 SQL 语句中。

Java 代码示例

List<Integer> employeeIds = Arrays.asList(1, 2, 3);

try (SqlSession session = sqlSessionFactory.openSession()) {
    EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
    List<Employee> employees = mapper.findEmployeesByIds(employeeIds);
    for (Employee employee : employees) {
        System.out.println(employee);
    }
}

7.2.2 高级用法

foreach 元素不仅可以用于 IN 查询,还可以用于批量的 INSERT、UPDATE 或 DELETE 操作。

批量插入

<insert id="insertEmployees">
  INSERT INTO employee (name, age) VALUES
  <foreach item="employee" index="index" collection="employeeList" separator=",">
    (#{employee.name}, #{employee.age})
  </foreach>
</insert>

Java 代码示例

List<Employee> newEmployees = Arrays.asList(
    new Employee("John", 25),
    new Employee("Jane", 30),
    new Employee("Doe", 35)
);

try (SqlSession session = sqlSessionFactory.openSession()) {
    EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
    mapper.insertEmployees(newEmployees);
    session.commit();
}

7.3 动态SQL-sql&include

在 MyBatis 中,sql 和 include 元素用于复用 SQL 代码片段,这样可以减少冗余代码并提高可维护性。通过定义一个可复用的 sql 元素并在需要的地方使用 include 元素来插入这个 SQL 片段,你可以让你的 MyBatis 映射文件更加整洁。

7.3.1 sql 元素

sql 元素用于定义一个可复用的 SQL 代码片段。
XML 配置示例

<sql id="employeeColumns">
  id, name, age, department
</sql>

在这个例子中,我们定义了一个名为 employeeColumns 的 sql 元素,这个元素包含了 employee 表中的列名。

7.3.2 include 元素

include 元素用于插入一个已定义的 sql 元素。
XML 配置示例

<select id="findEmployees" resultType="com.example.Employee">
  SELECT
  <include refid="employeeColumns"/>
  FROM employee
</select>

在这个例子中,include 元素通过 refid 属性引用了前面定义的 employeeColumns SQL 片段。

Java 代码示例

try (SqlSession session = sqlSessionFactory.openSession()) {
    EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
    List<Employee> employees = mapper.findEmployees();
    for (Employee employee : employees) {
        System.out.println(employee);
    }
}

7.3.3 高级用法

你还可以在 sql 元素中使用动态 SQL。

XML 配置示例

<sql id="dynamicWhere">
  <where>
    <if test="name != null">
      name = #{name}
    </if>
    <if test="age != null">
      AND age = #{age}
    </if>
  </where>
</sql>

<select id="findEmployeesByCondition" resultType="com.example.Employee">
  SELECT
  <include refid="employeeColumns"/>
  FROM employee
  <include refid="dynamicWhere"/>
</select>

这样,你可以在多个查询中复用相同的 WHERE 子句,而不需要每次都重新编写这些逻辑。

7.3.4 注意事项

  • 使用 sql 和 include 元素可以提高 SQL 代码的复用性,但也可能导致映射文件变得更加复杂。因此,在使用这些元素时,务必保持代码的整洁和可维护性。
  • 和其他所有 SQL 元素一样,注意防止 SQL 注入的风险。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值