Mybatis


Mybatis 介绍

ORM 介绍

ORM(Object Relational Mapping,对象关系映射):指的是持久化数据和实体对象的映射模式,为了解决面向对象与关系型数据库存在的互不匹配的现象的技术。

image

image

什么是 Mybatis ?

  1. Mybatis 是一个优秀的基于 Java 的持久层框架,它内部封装了 JDBC,使开发者只需要关注 SQL 语句本身,而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。

  2. 具体地说,Hibernate 是一个完全的 ORM 框架,而 Mybatis 是一个不完全的 ORM 框架。

  3. Mybatis 会将输入参数、输出结果进行映射。

MyBatis 官网地址

原生态 JDBC 操作的分析

原生态 JDBC 操作:

public static void main(String[] args) {
       <span class="hljs-type">Connection</span> <span class="hljs-variable">connection</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;
       <span class="hljs-type">PreparedStatement</span> <span class="hljs-variable">preparedStatement</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;
       <span class="hljs-type">ResultSet</span> <span class="hljs-variable">resultSet</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;

       <span class="hljs-keyword">try</span> {
          <span class="hljs-comment">// 1、加载数据库驱动</span>
          Class.forName(<span class="hljs-string">"com.mysql.jdbc.Driver"</span>);
          <span class="hljs-comment">// 2、通过驱动管理类获取数据库链接</span>
          connection =  DriverManager.getConnection(<span class="hljs-string">"jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8"</span>, <span class="hljs-string">"root"</span>, <span class="hljs-string">"root"</span>);
          <span class="hljs-comment">// 3、定义sql语句 ?表示占位符</span>
       <span class="hljs-type">String</span> <span class="hljs-variable">sql</span> <span class="hljs-operator">=</span> <span class="hljs-string">"select * from user where username = ?"</span>;
          <span class="hljs-comment">// 4、获取预处理statement</span>
          preparedStatement = connection.prepareStatement(sql);
          <span class="hljs-comment">// 5、设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值</span>
          preparedStatement.setString(<span class="hljs-number">1</span>, <span class="hljs-string">"王五"</span>);
          <span class="hljs-comment">// 6、向数据库发出sql执行查询,查询出结果集</span>
          resultSet =  preparedStatement.executeQuery();
          <span class="hljs-comment">// 7、遍历查询结果集</span>
          <span class="hljs-keyword">while</span>(resultSet.next()){
              User user
              System.out.println(resultSet.getString(<span class="hljs-string">"id"</span>)+<span class="hljs-string">"  "</span>+resultSet.getString(<span class="hljs-string">"username"</span>));
          }
       } <span class="hljs-keyword">catch</span> (Exception e) {
          e.printStackTrace();
       }<span class="hljs-keyword">finally</span>{
          <span class="hljs-comment">//8、释放资源</span>
          <span class="hljs-keyword">if</span>(resultSet!=<span class="hljs-literal">null</span>){
              <span class="hljs-keyword">try</span> {
                 resultSet.close();
              } <span class="hljs-keyword">catch</span> (SQLException e) {
                 <span class="hljs-comment">// TODO Auto-generated catch block</span>
                 e.printStackTrace();
              }
          }
          <span class="hljs-keyword">if</span>(preparedStatement!=<span class="hljs-literal">null</span>){
              <span class="hljs-keyword">try</span> {
                 preparedStatement.close();
              } <span class="hljs-keyword">catch</span> (SQLException e) {
                 <span class="hljs-comment">// TODO Auto-generated catch block</span>
                 e.printStackTrace();
              }
          }
          <span class="hljs-keyword">if</span>(connection!=<span class="hljs-literal">null</span>){
              <span class="hljs-keyword">try</span> {
                 connection.close();
              } <span class="hljs-keyword">catch</span> (SQLException e) {
                 <span class="hljs-comment">// TODO Auto-generated catch block</span>
                 e.printStackTrace();
              }
          }
       }
   }

原生态 JDBC 操作的问题与解决方案:

  • 问题:

    1. 频繁创建和销毁数据库的连接会造成系统资源浪费从而影响系统性能。
    2. sql 语句在代码中硬编码,如果要修改 sql 语句,就需要修改 java 代码,造成代码不易维护。
    3. 查询操作时,需要手动将结果集中的数据封装到实体对象中。
    4. 增删改查操作需要参数时,需要手动将实体对象的数据设置到 sql 语句的占位符。
  • 对应的解决方案:

    1. 使用数据库连接池初始化连接资源。
    2. 将 sql 语句抽取到配置文件中。
    3. 使用反射、内省等底层技术,将实体与表进行属性与字段的自动映射。

Mybatis 框架原理

Mybatis 通过 xml 或注解的方式将要执行的各种 statement 配置起来,并将 Java 对象和 statement 中 SQL 的动态参数进行映射,生成最终执行的 SQL 语句。最后 Mybatis 框架执行 SQL 并将结果映射为 Java 对象并返回。

image
image


MyBatis API

Resources(加载资源的工具类)

核心方法:

image

SqlSessionFactoryBuilder(构建器)

SqlSessionFactoryBuilder:获取 SqlSessionFactory 工厂对象的功能类

核心方法:

image

SqlSessionFactory(工厂对象)

SqlSessionFactory:获取 SqlSession 构建者对象的工厂接口

核心方法:

image

SqlSession 会话对象

SqlSession:构建者对象接口,用于执行 SQL、管理事务、接口代理

SqlSession 实例在 MyBatis 中是非常强大的一个类,在这里能看到所有执行语句、提交或回滚事务和获取映射器实例的方法。

image

Mybatis 入门案例

MyBatis 开发步骤:

  1. 添加 MyBatis 的 jar 包
  2. 创建 Student 数据表
  3. 编写 Student 实体类
  4. 编写映射文件 StudentMapper.xml
  5. 编写核心文件 MyBatisConfig.xml
  6. 编写测试类

环境搭建

1)导入 MyBatis 的 jar 包

  • mysql-connector-java-5.1.37-bin.jar
  • mybatis-3.5.3.jar
  • log4j-1.2.17.jar

或 maven 依赖:

<!-- mybatis 环境 -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.3</version>
</dependency>
<!-- mysql 环境 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.11</version>
</dependency>

2)创建 student 数据表

CREATE TABLE student(
    id INT PRIMARY KEY AUTO_INCREMENT,
    NAME VARCHAR(20),
    age INT
);

INSERT INTO student VALUES (NULL, '张三', 23);
INSERT INTO student VALUES (NULL, '李四', 24);
INSERT INTO student VALUES (NULL, '王五', 25);

3)编写 Student 实体类

public class Student {
<span class="hljs-keyword">private</span> Integer id;
<span class="hljs-keyword">private</span> String name;
<span class="hljs-keyword">private</span> Integer age;

<span class="hljs-keyword">public</span> <span class="hljs-title function_">Student</span><span class="hljs-params">()</span> {
}

<span class="hljs-keyword">public</span> <span class="hljs-title function_">Student</span><span class="hljs-params">(Integer id, String name, Integer age)</span> {
    <span class="hljs-built_in">this</span>.id = id;
    <span class="hljs-built_in">this</span>.name = name;
    <span class="hljs-built_in">this</span>.age = age;
}

<span class="hljs-keyword">public</span> Integer <span class="hljs-title function_">getId</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> id;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setId</span><span class="hljs-params">(Integer id)</span> {
    <span class="hljs-built_in">this</span>.id = id;
}

<span class="hljs-keyword">public</span> String <span class="hljs-title function_">getName</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> name;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setName</span><span class="hljs-params">(String name)</span> {
    <span class="hljs-built_in">this</span>.name = name;
}

<span class="hljs-keyword">public</span> Integer <span class="hljs-title function_">getAge</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> age;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setAge</span><span class="hljs-params">(Integer age)</span> {
    <span class="hljs-built_in">this</span>.age = age;
}

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> String <span class="hljs-title function_">toString</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Student{"</span> +
            <span class="hljs-string">"id="</span> + id +
            <span class="hljs-string">", name='"</span> + name + <span class="hljs-string">'\''</span> +
            <span class="hljs-string">", age="</span> + age +
            <span class="hljs-string">'}'</span>;
}

}

4)JDBC 配置文件

Mysql 5.X:

db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/world
db.username=root
db.password=admin

Mysql 8.X:

db.driver=com.mysql.cj.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/world?serverTimezone=UTC
db.username=root
db.password=admin

Mybatis 全局配置文件

全局配置文件包含了 MyBatis 全局的设置和属性信息,如数据库的连接、事务、连接池信息等。

全局配置文件可自定义命名,其配置内容和顺序如下(顺序不能乱):

  • Properties(属性)
  • Settings(全局参数设置)
  • typeAliases(类型别名)
  • typeHandlers(类型处理器)
  • objectFactory(对象工厂)
  • plugins(插件)
  • environments(环境信息集合)
    • environment(单个环境信息)
      • transactionManager(事务)
      • dataSource(数据源)
  • mappers(映射器)

示例:src 目录下的 MyBatisConfig.xml

  • jdbc.properties
db.driver=com.mysql.cj.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/world?serverTimezone=UTC
db.username=root
db.password=admin
  • MyBatisConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!-- MyBatis 的 DTD 约束 -->
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">

<!-- 根标签 -->
<configuration>

<span class="hljs-comment">&lt;!-- 引入数据库连接的配置文件 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">properties</span> <span class="hljs-attr">resource</span>=<span class="hljs-string">"jdbc.properties"</span>/&gt;</span>
<span class="hljs-comment">&lt;!--
 &lt;properties resource="db.properties"&gt;
       &lt;property name="db.username" value="123" /&gt;
 &lt;/properties&gt;
 --&gt;</span>

<span class="hljs-comment">&lt;!-- 在日常开发过程中,排查问题时难免需要输出 MyBatis 真正执行的 SQL 语句、参数、结果等信息,这时我们就可以借助 LOG4J 的功能来实现执行信息的输出 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">settings</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">setting</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"logImpl"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"log4j"</span>/&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">settings</span>&gt;</span>

<span class="hljs-comment">&lt;!-- 起别名:即全类名与别名的映射 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">typeAliases</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- 单个别名定义 --&gt;</span>
    <span class="hljs-comment">&lt;!-- &lt;typeAlias type="com.bean.Student" alias="student"/&gt; --&gt;</span>
    <span class="hljs-comment">&lt;!-- 批量别名定义(推荐) --&gt;</span>
    <span class="hljs-comment">&lt;!-- package:为指定包下的所有类声明别名,其默认别名就是类名(首字母大小写都可) --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">package</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"com.bean"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">typeAliases</span>&gt;</span>

<span class="hljs-comment">&lt;!-- environments 配置数据库环境:环境可以有多个,default属性指定使用的是哪个 --&gt;</span>
<span class="hljs-comment">&lt;!-- 与spring整合后,该信息由spring来管理 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">environments</span> <span class="hljs-attr">default</span>=<span class="hljs-string">"mysql"</span>&gt;</span>
    <span class="hljs-comment">&lt;!--environment 配置数据库环境:id属性唯一标识 --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">environment</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"mysql"</span>&gt;</span>
        <span class="hljs-comment">&lt;!-- 配置JDBC事务控制,由mybatis进行管理 type属性值表示采用JDBC默认的事务 --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">transactionManager</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"JDBC"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">transactionManager</span>&gt;</span>
        <span class="hljs-comment">&lt;!-- dataSource 数据源信息:type属性指表示采用mybatis连接池 --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dataSource</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"POOLED"</span>&gt;</span>
            <span class="hljs-comment">&lt;!-- property获取数据库连接的配置信息 --&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"driver"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"${db.driver}"</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"url"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"${db.url}"</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"username"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"${db.username}"</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"${db.password}"</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dataSource</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">environment</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">environments</span>&gt;</span>

<span class="hljs-comment">&lt;!-- mappers引入映射配置文件 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">mappers</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- mapper 引入指定的映射配置文件。resource属性指定映射配置文件的名称 --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">mapper</span> <span class="hljs-attr">resource</span>=<span class="hljs-string">"StudentMapper.xml"</span>/&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">mappers</span>&gt;</span>

</configuration>

加载的顺序:

  1. 先加载 properties 中 property 标签声明的属性;
  2. 再加载 properties 标签引入的 java 配置文件中的属性;
  3. parameterType 的值和 properties 的属性值会有冲突关系(因此最好给配置文件属性加上前缀 db. 加以区分)。

Mybatis 的默认别名:

image

Mapper:

  • <mapper resource=''/>

    • 使用相对于类路径的资源
    • 如:<mapper resource="sqlmap/User.xml" />
  • <mapper url=''/>

    • 使用完全限定路径
    • 如:<mapper url="file:///D:\workspace_spingmvc\mybatis_01\config\sqlmap\User.xml" />
  • <mapper class=''/>

    • 使用 mapper 接口的全限定名
    • 如:<mapper class="com.mybatis.mapper.UserMapper"/>
    • 注意:此种方法要求 mapper 接口和 mapper 映射文件要名称相同,且放到同一个目录下;
  • <package name=''/>(推荐)

    • 注册指定包下的所有映射文件
    • 如:<package name="com.mybatis.mapper"/>
    • 注意:此种方法要求 mapper 接口和 mapper 映射文件要名称相同,且放到同一个目录下。

Mybatis 映射配置文件

映射配置文件包含了数据和对象之间的映射关系以及要执行的 SQL 语句。

映射文件可自定义命名,一般按照规范实体类名Mapper.xml,这种命名规范是由 ibatis 遗留下来的。

示例:src 目录下的 StudentMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!--MyBatis 的 DTD 约束 -->
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--
mapper:核心根标签
namespace:命名空间,对 statement 的信息进行分类管理(在 mapper 代理时,它具有特殊及重要的作用)
-->

<mapper namespace="StudentMapper">

<span class="hljs-comment">&lt;!--
    select:查询功能的标签,表示一个MappedStatement对象
    id属性:statement的唯一标识
    #{}:表示一个占位符(即?)
    #{id}:里面的id表示输入参数的参数名称
    resultType属性:输出结果的所映射的Java类型(单条结果所对应的Java类型)
        这里的student之所以不用写全类名,是因为会在后面的全局配置文件中起别名
    parameterType属性:输入参数的所属Java类型
--&gt;</span>
<span class="hljs-comment">&lt;!-- 查询全量学生信息 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"selectAll"</span> <span class="hljs-attr">resultType</span>=<span class="hljs-string">"student"</span>&gt;</span>
    SELECT * FROM student
<span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span>

<span class="hljs-comment">&lt;!-- 根据id查询指定学生信息 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"selectById"</span> <span class="hljs-attr">resultType</span>=<span class="hljs-string">"student"</span> <span class="hljs-attr">parameterType</span>=<span class="hljs-string">"int"</span>&gt;</span>
    SELECT * FROM student WHERE id = #{id}
<span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span>

<span class="hljs-comment">&lt;!-- 根据名称模糊查询学生列表 --&gt;</span>
<span class="hljs-comment">&lt;!-- #{} 表示占位符 ?,#{} 接收简单类型的参数时,里面的名称可以任意 --&gt;</span>
<span class="hljs-comment">&lt;!-- ${} 表示拼接符,${} 接收简单类型的参数时,里面的名称必须是 value --&gt;</span>
<span class="hljs-comment">&lt;!-- ${} 里面的值会原样输出,不加解析(如果该参数值是字符串,也不会添加引号) --&gt;</span>
<span class="hljs-comment">&lt;!-- ${} 存在sql注入的风险,但是有些场景下必须使用,比如排序后面需要动态传入排序的列名 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"selectByName"</span> <span class="hljs-attr">parameterType</span>=<span class="hljs-string">"String"</span> <span class="hljs-attr">resultType</span>=<span class="hljs-string">"student"</span>&gt;</span>
    SELECT * FROM student WHERE name LIKE '%${value}%'
<span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span>

<span class="hljs-comment">&lt;!-- 添加学生信息 --&gt;</span>
<span class="hljs-comment">&lt;!-- selectKey:查询主键,在标签内需要输入查询主键的sql --&gt;</span>
<span class="hljs-comment">&lt;!-- order:指定查询主键的sql和insert语句的执行顺序,相当于insert语句来说 --&gt;</span>
<span class="hljs-comment">&lt;!-- LAST_INSERT_ID:该函数是mysql的函数,获取自增主键的ID,它必须配合insert语句一起使用 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">insert</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"insertBySelectLastId"</span> <span class="hljs-attr">parameterType</span>=<span class="hljs-string">"student"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">selectKey</span> <span class="hljs-attr">keyProperty</span>=<span class="hljs-string">"id"</span> <span class="hljs-attr">resultType</span>=<span class="hljs-string">"int"</span> <span class="hljs-attr">order</span>=<span class="hljs-string">"AFTER"</span>&gt;</span>
        SELECT LAST_INSERT_ID()
    <span class="hljs-tag">&lt;/<span class="hljs-name">selectKey</span>&gt;</span>
    INSERT INTO student (name, age) VALUES (#{name},#{age})
<span class="hljs-tag">&lt;/<span class="hljs-name">insert</span>&gt;</span>

<span class="hljs-comment">&lt;!-- 添加学生信息 --&gt;</span>
<span class="hljs-comment">&lt;!-- 只要不是主键自增,order都设置被before --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">insert</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"insertByKeyproperty"</span> <span class="hljs-attr">parameterType</span>=<span class="hljs-string">"student"</span> <span class="hljs-attr">useGeneratedKeys</span>=<span class="hljs-string">"true"</span> <span class="hljs-attr">keyProperty</span>=<span class="hljs-string">"id"</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- 需要显式地给id赋值,因为该id的值不是通过自增主键来创建的 --&gt;</span>
    INSERT INTO student (id,name,age)
    VALUES(#{id}, #{name}, #{age})
<span class="hljs-tag">&lt;/<span class="hljs-name">insert</span>&gt;</span>

<span class="hljs-comment">&lt;!-- 修改学生信息 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">update</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"updateById"</span> <span class="hljs-attr">parameterType</span>=<span class="hljs-string">"student"</span>&gt;</span>
    UPDATE student SET name = #{name}, age = #{age} WHERE id = #{id}
<span class="hljs-tag">&lt;/<span class="hljs-name">update</span>&gt;</span>

<span class="hljs-comment">&lt;!-- 删除学生信息 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">delete</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"deleteById"</span> <span class="hljs-attr">parameterType</span>=<span class="hljs-string">"int"</span>&gt;</span>
    DELETE FROM student WHERE id = #{id}
<span class="hljs-tag">&lt;/<span class="hljs-name">delete</span>&gt;</span>

</mapper>

测试代码

import com.bean.Student;
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.jupiter.api.Test;

import java.io.InputStream;
import java.util.List;

public class StudentTest {

<span class="hljs-comment">// 查询全量结果</span>
<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">selectAll</span><span class="hljs-params">()</span> {
    <span class="hljs-type">InputStream</span> <span class="hljs-variable">inputStream</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;
    <span class="hljs-type">SqlSession</span> <span class="hljs-variable">sqlSession</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// 1. 加载核心配置文件</span>
        inputStream = Resources.getResourceAsStream(<span class="hljs-string">"MyBatisConfig.xml"</span>);
        <span class="hljs-comment">// 2. 获取SqlSession工厂对象</span>
        <span class="hljs-type">SqlSessionFactory</span> <span class="hljs-variable">ssf</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(inputStream);
        <span class="hljs-comment">// 3. 通过SqlSession工厂对象获取SqlSession对象</span>
        <span class="hljs-comment">// sqlSession 内部的数据区域本身就是一级缓存,是通过 map 来存储的</span>
        sqlSession = ssf.openSession();
        <span class="hljs-comment">// 4. 执行映射配置文件中的SQL,并获取返回结果</span>
        List&lt;Student&gt; students = sqlSession.selectList(<span class="hljs-string">"StudentMapper.selectAll"</span>);  <span class="hljs-comment">// 映射配置文件中的namespace属性值.(SQL的)唯一标识</span>
        <span class="hljs-comment">// 5. 处理返回结果</span>
        <span class="hljs-keyword">for</span> (Student s : students) {
            System.out.println(s);
        }
    } <span class="hljs-keyword">catch</span> (Exception e) {
        e.printStackTrace();
    } <span class="hljs-keyword">finally</span> {
        sqlSession.close();
        <span class="hljs-keyword">try</span> {
            inputStream.close();
        } <span class="hljs-keyword">catch</span> (Exception e) {
            e.printStackTrace();
        }
    }
}

<span class="hljs-comment">// 根据id查询指定结果</span>
<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">selectById</span><span class="hljs-params">()</span> {
    <span class="hljs-type">InputStream</span> <span class="hljs-variable">inputStream</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;
    <span class="hljs-type">SqlSession</span> <span class="hljs-variable">sqlSession</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// 1. 加载核心配置文件</span>
        inputStream = Resources.getResourceAsStream(<span class="hljs-string">"MyBatisConfig.xml"</span>);
        <span class="hljs-comment">// 2. 获取SqlSession工厂对象</span>
        <span class="hljs-type">SqlSessionFactory</span> <span class="hljs-variable">ssf</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(inputStream);
        <span class="hljs-comment">// 3. 通过SqlSession工厂对象获取SqlSession对象</span>
        sqlSession = ssf.openSession();
        <span class="hljs-comment">// 4. 执行映射配置文件中的SQL,并获取返回结果</span>
        <span class="hljs-type">Student</span> <span class="hljs-variable">student</span> <span class="hljs-operator">=</span> sqlSession.selectOne(<span class="hljs-string">"StudentMapper.selectById"</span>, <span class="hljs-number">2</span>);
        <span class="hljs-comment">// 5. 处理返回结果</span>
        System.out.println(student);
    } <span class="hljs-keyword">catch</span> (Exception e) {
        e.printStackTrace();
    } <span class="hljs-keyword">finally</span> {
        sqlSession.close();
        <span class="hljs-keyword">try</span> {
            inputStream.close();
        } <span class="hljs-keyword">catch</span> (Exception e) {
            e.printStackTrace();
        }
    }
}

<span class="hljs-comment">// 根据名称模糊查询结果</span>
<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">SelectByName</span><span class="hljs-params">()</span> {
    <span class="hljs-type">InputStream</span> <span class="hljs-variable">inputStream</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;
    <span class="hljs-type">SqlSession</span> <span class="hljs-variable">sqlSession</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// 1. 加载核心配置文件</span>
        inputStream = Resources.getResourceAsStream(<span class="hljs-string">"MyBatisConfig.xml"</span>);
        <span class="hljs-comment">// 2. 获取SqlSession工厂对象</span>
        <span class="hljs-type">SqlSessionFactory</span> <span class="hljs-variable">ssf</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(inputStream);
        <span class="hljs-comment">// 3. 通过SqlSession工厂对象获取SqlSession对象</span>
        sqlSession = ssf.openSession();
        <span class="hljs-comment">// 4. 执行映射配置文件中的SQL,并获取返回结果</span>
        List&lt;Student&gt; students = sqlSession.selectList(<span class="hljs-string">"StudentMapper.selectByName"</span>, <span class="hljs-string">"五"</span>);
        <span class="hljs-comment">// 5. 处理返回结果</span>
        <span class="hljs-keyword">for</span> (Student s : students) {
            System.out.println(s);
        }
    } <span class="hljs-keyword">catch</span> (Exception e) {
        e.printStackTrace();
    } <span class="hljs-keyword">finally</span> {
        sqlSession.close();
        <span class="hljs-keyword">try</span> {
            inputStream.close();
        } <span class="hljs-keyword">catch</span> (Exception e) {
            e.printStackTrace();
        }
    }
}

<span class="hljs-comment">// 新增数据:根据mysql函数自动获取id</span>
<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">insertBySelectLastId</span><span class="hljs-params">()</span> {
    <span class="hljs-type">InputStream</span> <span class="hljs-variable">inputStream</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;
    <span class="hljs-type">SqlSession</span> <span class="hljs-variable">sqlSession</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// 1. 加载核心配置文件</span>
        inputStream = Resources.getResourceAsStream(<span class="hljs-string">"MyBatisConfig.xml"</span>);
        <span class="hljs-comment">// 2. 获取SqlSession工厂对象</span>
        <span class="hljs-type">SqlSessionFactory</span> <span class="hljs-variable">ssf</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(inputStream);
        <span class="hljs-comment">// 3. 通过SqlSession工厂对象获取SqlSession对象</span>
        sqlSession = ssf.openSession();
        <span class="hljs-comment">// 4. 执行映射配置文件中的SQL,并获取返回结果</span>
        <span class="hljs-type">Student</span> <span class="hljs-variable">student</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Student</span>(<span class="hljs-literal">null</span>, <span class="hljs-string">"王八"</span>, <span class="hljs-number">29</span>);  <span class="hljs-comment">// id会自动填充</span>
        <span class="hljs-type">int</span> <span class="hljs-variable">result</span> <span class="hljs-operator">=</span> sqlSession.insert(<span class="hljs-string">"StudentMapper.insertBySelectLastId"</span>, student);
        <span class="hljs-comment">// 5. 处理返回结果</span>
        <span class="hljs-keyword">if</span> (result==<span class="hljs-number">1</span>) {
            System.out.println(<span class="hljs-string">"insertBySelectLastId 新增成功"</span>);
            <span class="hljs-comment">// 需要手动提交事务</span>
            sqlSession.commit();
        } <span class="hljs-keyword">else</span> {
            System.out.println(<span class="hljs-string">"insertBySelectLastId 新增失败"</span>);
        }
    } <span class="hljs-keyword">catch</span> (Exception e) {
        e.printStackTrace();
    } <span class="hljs-keyword">finally</span> {
        sqlSession.close();
        <span class="hljs-keyword">try</span> {
            inputStream.close();
        } <span class="hljs-keyword">catch</span> (Exception e) {
            e.printStackTrace();
        }
    }
}

<span class="hljs-comment">// 新增数据:根据映射配置属性,自动获取id</span>
<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">insertByKeyproperty</span><span class="hljs-params">()</span> {
    <span class="hljs-type">InputStream</span> <span class="hljs-variable">inputStream</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;
    <span class="hljs-type">SqlSession</span> <span class="hljs-variable">sqlSession</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// 1. 加载核心配置文件</span>
        inputStream = Resources.getResourceAsStream(<span class="hljs-string">"MyBatisConfig.xml"</span>);
        <span class="hljs-comment">// 2. 获取SqlSession工厂对象</span>
        <span class="hljs-type">SqlSessionFactory</span> <span class="hljs-variable">ssf</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(inputStream);
        <span class="hljs-comment">// 3. 通过SqlSession工厂对象获取SqlSession对象</span>
        sqlSession = ssf.openSession();
        <span class="hljs-comment">// 4. 执行映射配置文件中的SQL,并获取返回结果</span>
        <span class="hljs-type">Student</span> <span class="hljs-variable">student</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Student</span>(<span class="hljs-literal">null</span>, <span class="hljs-string">"史十"</span>, <span class="hljs-number">29</span>);  <span class="hljs-comment">// id会自动填充</span>
        <span class="hljs-type">int</span> <span class="hljs-variable">result</span> <span class="hljs-operator">=</span> sqlSession.insert(<span class="hljs-string">"StudentMapper.insertByKeyproperty"</span>, student);
        <span class="hljs-comment">// 5. 处理返回结果</span>
        <span class="hljs-keyword">if</span> (result==<span class="hljs-number">1</span>) {
            System.out.println(<span class="hljs-string">"insertByKeyproperty 新增成功"</span>);
            <span class="hljs-comment">// 需要手动提交事务</span>
            sqlSession.commit();
        } <span class="hljs-keyword">else</span> {
            System.out.println(<span class="hljs-string">"insertByKeyproperty 新增失败"</span>);
        }
    } <span class="hljs-keyword">catch</span> (Exception e) {
        e.printStackTrace();
    } <span class="hljs-keyword">finally</span> {
        sqlSession.close();
        <span class="hljs-keyword">try</span> {
            inputStream.close();
        } <span class="hljs-keyword">catch</span> (Exception e) {
            e.printStackTrace();
        }
    }
}

<span class="hljs-comment">// 修改数据</span>
<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">updateById</span><span class="hljs-params">()</span> {
    <span class="hljs-type">InputStream</span> <span class="hljs-variable">inputStream</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;
    <span class="hljs-type">SqlSession</span> <span class="hljs-variable">sqlSession</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// 1. 加载核心配置文件</span>
        inputStream = Resources.getResourceAsStream(<span class="hljs-string">"MyBatisConfig.xml"</span>);
        <span class="hljs-comment">// 2. 获取SqlSession工厂对象</span>
        <span class="hljs-type">SqlSessionFactory</span> <span class="hljs-variable">ssf</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(inputStream);
        <span class="hljs-comment">// 3. 通过SqlSession工厂对象获取SqlSession对象</span>
        sqlSession = ssf.openSession();
        <span class="hljs-comment">// 4. 执行映射配置文件中的SQL,并获取返回结果</span>
        <span class="hljs-type">Student</span> <span class="hljs-variable">student</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Student</span>(<span class="hljs-number">2</span>, <span class="hljs-string">"小二"</span>, <span class="hljs-number">29</span>);
        <span class="hljs-type">int</span> <span class="hljs-variable">result</span> <span class="hljs-operator">=</span> sqlSession.update(<span class="hljs-string">"StudentMapper.updateById"</span>, student);
        <span class="hljs-comment">// 5. 处理返回结果</span>
        <span class="hljs-keyword">if</span> (result==<span class="hljs-number">1</span>) {
            System.out.println(<span class="hljs-string">"updateById 修改成功"</span>);
            <span class="hljs-comment">// 需要手动提交事务</span>
            sqlSession.commit();
        } <span class="hljs-keyword">else</span> {
            System.out.println(<span class="hljs-string">"updateById 修改失败"</span>);
        }
    } <span class="hljs-keyword">catch</span> (Exception e) {
        e.printStackTrace();
    } <span class="hljs-keyword">finally</span> {
        sqlSession.close();
        <span class="hljs-keyword">try</span> {
            inputStream.close();
        } <span class="hljs-keyword">catch</span> (Exception e) {
            e.printStackTrace();
        }
    }
}

<span class="hljs-comment">// 删除数据</span>
<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">deleteById</span><span class="hljs-params">()</span> {
    <span class="hljs-type">InputStream</span> <span class="hljs-variable">inputStream</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;
    <span class="hljs-type">SqlSession</span> <span class="hljs-variable">sqlSession</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// 1. 加载核心配置文件</span>
        inputStream = Resources.getResourceAsStream(<span class="hljs-string">"MyBatisConfig.xml"</span>);
        <span class="hljs-comment">// 2. 获取SqlSession工厂对象</span>
        <span class="hljs-type">SqlSessionFactory</span> <span class="hljs-variable">ssf</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(inputStream);
        <span class="hljs-comment">// 3. 通过SqlSession工厂对象获取SqlSession对象</span>
        sqlSession = ssf.openSession();
        <span class="hljs-comment">// 4. 执行映射配置文件中的SQL,并获取返回结果</span>
        <span class="hljs-type">int</span> <span class="hljs-variable">result</span> <span class="hljs-operator">=</span> sqlSession.delete(<span class="hljs-string">"StudentMapper.deleteById"</span>, <span class="hljs-number">2</span>);
        <span class="hljs-comment">// 5. 处理返回结果</span>
        <span class="hljs-keyword">if</span> (result==<span class="hljs-number">1</span>) {
            System.out.println(<span class="hljs-string">"updateById 删除成功"</span>);
            <span class="hljs-comment">// 需要手动提交事务</span>
            sqlSession.commit();
        } <span class="hljs-keyword">else</span> {
            System.out.println(<span class="hljs-string">"updateById 删除失败"</span>);
        }
    } <span class="hljs-keyword">catch</span> (Exception e) {
        e.printStackTrace();
    } <span class="hljs-keyword">finally</span> {
        sqlSession.close();
        <span class="hljs-keyword">try</span> {
            inputStream.close();
        } <span class="hljs-keyword">catch</span> (Exception e) {
            e.printStackTrace();
        }
    }
}

}

输入 / 输出映射详解

输入映射:parameterType

1)简单类型

如学生 id 等基本数据类型。

2)POJO 类型

POJO(Plain Ordinary Java Object)即简单的 Java 对象,实际就是普通 Java Beans。

3)包装 POJO 类型

包装 POJO 类型,即 Java 对象中有其他 Java 对象的引用。

  1. 需求:
    综合查询时,可能会根据用户信息、商品信息、订单信息等作为条件进行查询,用户信息中的查询条件由用户的名称和性别进行查询。

  2. 创建包装 POJO 类型:
    image

  3. 映射文件:
    image

  4. Mapper 接口:
    image

  5. 测试代码:
    image

4)Map 类型

同传递 POJO 对象一样,Map 的 key 相当于 POJO 的属性。

  • 映射文件:
<!-- 传递 hashmap 综合查询用户信息 -->
<select id="findUserByHashmap" parameterType="hashmap" resultType="user">
    <!-- username 是 hashmap 的 key -->
    select * from user where id=#{id} and username like '%${username}%'
</select>
  • 测试代码:
Public void testFindUserByHashmap()throws Exception{
    // 获取 session
    SqlSession session = sqlSessionFactory.openSession();
    // 获限 mapper 接口实例
    UserMapper userMapper = session.getMapper(UserMapper.class);
    // 构造查询条件 Hashmap 对象
    HashMap<String, Object> map = new HashMap<String, Object>();
    map.put("id", 1);
    map.put("username", "管理员");
<span class="hljs-comment">// 传递Hashmap对象查询用户列表</span>
List&lt;User&gt;list = userMapper.findUserByHashmap(map);
<span class="hljs-comment">// 关闭session</span>
session.close();

}

注意:当传递的 map 中的 key 和 sql 中解析的 key 不一致时,程序不会报错,只是通过 key 获取的值为空。


输出映射

resultType

使用要求:

  • 使用 resultType 进行结果映射时,需要查询出的列名和映射的对象的属性名一致,才能映射成功。
  • 如果查询的列名和对象的属性名全部不一致,那么映射的对象为空。
  • 如果查询的列名和对象的属性名有一个一致,那么映射的对象不为空,但是只有映射正确那一个属性才有值。
  • 如果查询的 SQL 的列名有别名,那么这个别名就需要是和属性映射的列名。

resultMap

使用要求

  • 使用 resultMap 进行结果映射时,不需要查询的列名和映射的属性名必须一致,但是需要声明一个 resultMap,来对列名和属性名进行映射。

示例需求

对以下 SQL 查询的结果集进行对象映射:Select id id_, username username_, sex sex_ from user where id = 1;

  • 映射文件:
<!-- resultMap 入门 -->
<!-- id 标签:专门为查询结果中唯一列映射 -->
<!-- result 标签:映射查询结果中的普通列 -->
<resultMap type="user" id="UserRstMap">
    <id column="id_" property="id" />
    <result column="username_" property="username" />
    <result column="sex_" property="sex" />
</resultMap>
<select id="findUserRstMap" parameterType="int" resultMap="UserRstMap">
    Select id id_,username username_,sex sex_ from user where id = #{id}
</select>
  • Mapper 接口:
    image

  • 测试代码:
    image


Mybatis Mapper 代理开发

传统 Dao 开发方式的问题

原始 Dao 的开发方式,即开发 Dao 接口和 Dao 实现类。

Dao 接口:

import com.bean.Student;

import java.util.List;

public interface StudentDao {

<span class="hljs-comment">// 1. 根据学生ID查询学生信息 </span>
<span class="hljs-keyword">public</span> Student <span class="hljs-title function_">selectById</span><span class="hljs-params">(<span class="hljs-type">int</span> id)</span>;

<span class="hljs-comment">// 2. 根据学生名称模糊查询学生列表 </span>
<span class="hljs-keyword">public</span> List&lt;Student&gt; <span class="hljs-title function_">selectByName</span><span class="hljs-params">(String name)</span>;

<span class="hljs-comment">// 3. 添加学生 </span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">insertBySelectLastId</span><span class="hljs-params">(Student Student)</span>;

}

Dao 实现类:

  • SqlSessionFactory:它的生命周期,应该是应用范围,即全局范围只有一个工厂,因此使用单例模式来实现这个功能(与 Spring 集成之后,由 Spring 来对其进行单例管理)。
  • SqlSession:它内部含有一块数据区域,存在线程不安全的问题,所以应该将 Sqlsession 声明到方法内部。
import com.bean.Student;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import java.util.List;

public class StudentDaoImpl implements StudentDao {

<span class="hljs-comment">// 依赖注入</span>
<span class="hljs-keyword">private</span> SqlSessionFactory sqlSessionFactory;

<span class="hljs-keyword">public</span> <span class="hljs-title function_">StudentDaoImpl</span><span class="hljs-params">(SqlSessionFactory sqlSessionFactory)</span> {
    <span class="hljs-built_in">this</span>.sqlSessionFactory = sqlSessionFactory;
}

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> Student <span class="hljs-title function_">selectById</span><span class="hljs-params">(<span class="hljs-type">int</span> id)</span> {
    <span class="hljs-comment">// 创建SqlSession</span>
    <span class="hljs-type">SqlSession</span> <span class="hljs-variable">sqlSession</span> <span class="hljs-operator">=</span> sqlSessionFactory.openSession();
    <span class="hljs-comment">// 调用SqlSession的增删改查方法</span>
    <span class="hljs-comment">// 第一个参数:表示statement的唯一标示</span>
    <span class="hljs-type">Student</span> <span class="hljs-variable">student</span> <span class="hljs-operator">=</span> sqlSession.selectOne(<span class="hljs-string">"StudentMapper.selectById"</span>, id);
    System.out.println(student);
    <span class="hljs-comment">// 关闭资源</span>
    sqlSession.close();
    <span class="hljs-keyword">return</span> student;
}

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> List&lt;Student&gt; <span class="hljs-title function_">selectByName</span><span class="hljs-params">(String name)</span> {
    <span class="hljs-comment">// 创建SqlSession</span>
    <span class="hljs-type">SqlSession</span> <span class="hljs-variable">sqlSession</span> <span class="hljs-operator">=</span> sqlSessionFactory.openSession();
    <span class="hljs-comment">// 调用SqlSession的增删改查方法</span>
    <span class="hljs-comment">// 第一个参数:表示statement的唯一标示</span>
    List&lt;Student&gt; list = sqlSession.selectList(<span class="hljs-string">"StudentMapper.SelectByName"</span>, name);
    System.out.println(list.toString());
    <span class="hljs-comment">// 关闭资源</span>
    sqlSession.close();
    <span class="hljs-keyword">return</span> list;
}

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">insertBySelectLastId</span><span class="hljs-params">(Student Student)</span> {
    <span class="hljs-comment">// 创建SqlSession</span>
    <span class="hljs-type">SqlSession</span> <span class="hljs-variable">sqlSession</span> <span class="hljs-operator">=</span> sqlSessionFactory.openSession();
    <span class="hljs-comment">// 调用SqlSession的增删改查方法</span>
    <span class="hljs-comment">// 第一个参数:表示statement的唯一标示</span>
    sqlSession.insert(<span class="hljs-string">"StudentMapper.insertBySelectLastId"</span>, Student);
    System.out.println(Student.getId());
    <span class="hljs-comment">// 提交事务</span>
    sqlSession.commit();
    <span class="hljs-comment">// 关闭资源</span>
    sqlSession.close();
}

}

测试类:

import com.bean.Student;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;

public class StudentDaoTest {

<span class="hljs-keyword">private</span> SqlSessionFactory sqlSessionFactory;

<span class="hljs-meta">@Before</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setUp</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> IOException {
    <span class="hljs-comment">// 1. 加载核心配置文件</span>
    <span class="hljs-type">InputStream</span> <span class="hljs-variable">inputStream</span> <span class="hljs-operator">=</span> Resources.getResourceAsStream(<span class="hljs-string">"MyBatisConfig.xml"</span>);
    <span class="hljs-comment">// 2. 获取SqlSession工厂对象</span>
    sqlSessionFactory = <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(inputStream);
}

<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">testSelectStudentById</span><span class="hljs-params">()</span> {
    <span class="hljs-type">StudentDao</span> <span class="hljs-variable">studentDao</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">StudentDaoImpl</span>(sqlSessionFactory);
    <span class="hljs-type">Student</span> <span class="hljs-variable">student</span> <span class="hljs-operator">=</span> studentDao.selectById(<span class="hljs-number">1</span>);
    System.out.println(student);
}

}

思考存在的问题:

  • 有大量的重复的模板代码。
  • 存在硬编码。

Mapper 代理的开发方式

采用 Mybatis 的代理开发方式实现 Dao 层的开发,是企业的主流方式。

Mapper 接口开发方法只需要程序员编写 Mapper 接口(相当于 Dao 接口),由 Mybatis 框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边 Dao 接口实现类方法。

总结代理方式可以让我们只编写接口即可,而实现类对象由 MyBatis 生成

Mapper 代理的开发规范

  1. Mapper.xml(映射文件)文件中的 namespace 与 mapper 接口的全限定名相同。
  2. Mapper 接口方法名和 Mapper.xml 中定义的每个 statement 的 id 相同。
  3. Mapper 接口方法的输入参数类型和 mapper.xml 中定义的每个 sql 的 parameterType 的类型相同。
  4. Mapper 接口方法的输出参数类型和 mapper.xml 中定义的每个 sql 的 resultType 的类型相同。

image

总结

Mapper 接口开发的方式: 程序员只需定义接口就可以对数据库进行操作。那么具体的对象是怎么创建的?

  1. 程序员负责定义接口;
  2. Mybatis 框架根据接口,通过动态代理的方式生成代理对象,负责数据库的 crud 操作。

代码示例:

  • Mapper 接口
import com.bean.Student;

import java.util.List;

public interface StudentMapper {
// 查询全部
public abstract List<Student> selectAll();

<span class="hljs-comment">// 根据id查询</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> Student <span class="hljs-title function_">selectById</span><span class="hljs-params">(Integer id)</span>;

<span class="hljs-comment">// 新增数据</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> Integer <span class="hljs-title function_">insert</span><span class="hljs-params">(Student stu)</span>;

<span class="hljs-comment">// 修改数据</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> Integer <span class="hljs-title function_">update</span><span class="hljs-params">(Student stu)</span>;

<span class="hljs-comment">// 删除数据</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> Integer <span class="hljs-title function_">delete</span><span class="hljs-params">(Integer id)</span>;

<span class="hljs-comment">// 多条件查询</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> List&lt;Student&gt; <span class="hljs-title function_">selectCondition</span><span class="hljs-params">(Student stu)</span>;

<span class="hljs-comment">// 根据多个id查询</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> List&lt;Student&gt; <span class="hljs-title function_">selectByIds</span><span class="hljs-params">(List&lt;Integer&gt; ids)</span>;

}

  • 测试类
import com.bean.Student;

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.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;

public class StudentMapperTest {

<span class="hljs-keyword">private</span> SqlSessionFactory sqlSessionFactory;

<span class="hljs-meta">@Before</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setUp</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> IOException {
    <span class="hljs-comment">// 加载核心配置文件</span>
    <span class="hljs-type">InputStream</span> <span class="hljs-variable">inputStream</span> <span class="hljs-operator">=</span> Resources.getResourceAsStream(<span class="hljs-string">"MyBatisConfig.xml"</span>);
    <span class="hljs-comment">// 获取SqlSession工厂对象</span>
    sqlSessionFactory = <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(inputStream);
}

<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">testSelectStudentById</span><span class="hljs-params">()</span> {
    <span class="hljs-type">SqlSession</span> <span class="hljs-variable">sqlSession</span> <span class="hljs-operator">=</span> sqlSessionFactory.openSession();
    <span class="hljs-comment">// 由mybatis通过sqlSession来创建代理对象</span>
    <span class="hljs-comment">// 创建StudentMapper对象</span>
    <span class="hljs-type">StudentMapper</span> <span class="hljs-variable">mapper</span> <span class="hljs-operator">=</span> sqlSession.getMapper(StudentMapper.class);
    <span class="hljs-type">Student</span> <span class="hljs-variable">student</span> <span class="hljs-operator">=</span> mapper.selectById(<span class="hljs-number">1</span>);
    System.out.println(student);
    <span class="hljs-comment">// 关闭资源</span>
    sqlSession.close();
    inputStream.close();
}

}

动态代理方式源码分析

分析动态代理对象如何生成的?

通过动态代理开发模式,我们只编写一个接口,不写实现类,我们通过 getMapper() 方法最终获取到 org.apache.ibatis.binding.MapperProxy 代理对象,然后执行功能,而这个代理对象正是 MyBatis 使用了 JDK 的动态代理技术,帮助我们生成了代理实现类对象。从而可以进行相关持久化操作。

分析方法是如何执行的?

动态代理实现类对象在执行方法的时候最终调用了 mapperMethod.execute() 方法,这个方法中通过 switch 语句根据操作类型来判断是新增、修改、删除、查询操作,最后一步回到了 MyBatis 最原生的 SqlSession 方式来执行增删改查。


动态 SQL

在 Mybatis 中提供了一些动态 SQL 标签,可以让程序员更快的进行 Mybatis 的开发,这些动态 SQL 可以提高 SQL 的可重用性。

动态 SQL 指的就是 SQL 语句可以根据条件或者参数的不同,而进行动态的变化。

常用的动态 SQL 标签有 if 标签、where 标签、SQL 片段、foreach 标签。

if、where 标签

if 和 where 标签可用于根据实体类的不同取值,使用不同的 SQL 语句来进行查询。

比如在 id 不为空时可以根据 id 查询,在 username 不为空时还要加入用户名作为条件等。这种情况在我们的多条件组合查询中经常会碰到。

使用格式:

<!-- where:条件标签。如果有动态条件,则使用该标签代替 where 关键字 -->
<where>
    <!-- if:条件判断标签 -->
    <if test="条件判断">
        查询条件拼接
    </if>

示例:

  • 映射文件:
<select id="findByCondition" parameterType="student" resultType="student">
    select * from student
    <where>
        <if test="id!=0">
            and id=#{id}
        </if>
        <if test="username!=null">
            and username=#{username}
        </if>
    </where>
</select>
  • 当查询条件 id 和 username 都存在时
     // 获得 MyBatis 框架生成的 StudentMapper 接口的实现类
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    Student condition = new Student();
    condition.setId(1);
    condition.setUsername("lucy");
    Student student = mapper.findByCondition(condition);

image

  • 当查询条件只有 id 存在时:
// 获得 MyBatis 框架生成的 UserMapper 接口的实现类
StudentMapper mapper = sqlSession.getMapper( StudentMapper.class);
    Student condition = new Student();
    condition.setId(1);
    Student student = mapper.findByCondition(condition);

image

foreach 标签

<foreach> 即循环遍历标签。适用于多个参数或者的关系。

使用语法:

<foreach collection="" open="" close="" item="" separator="">
    获取参数
</foreach>
  • collection:参数容器类型(list 集合、array 数组 )
  • open:开始的 SQL 语句
  • close:结束的 SQL 语句
  • item:参数变量名
  • separator:分隔符

示例需求:

循环执行 SQL 的拼接操作,例如:SELECT * FROM student WHERE id IN (1, 2, 5);

  • 映射文件:
<select id="findByIds" parameterType="list" resultType="student">
    select * from student
    <where>
        <foreach collection="list" open="id in(" close=")" item="id" separator=",">
            #{id}
        </foreach>
    </where>
</select>
  • 测试代码:
// 获得 MyBatis 框架生成的 UserMapper 接口的实现类
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(2);
List<Student> sList = mapper.findByIds(ids);
System.out.println(sList);

SQL 片段抽取

将重复的 SQL 提取出来,使用时用 include 引用即可,最终达到 SQL 重用的目的。

使用语法:

<!-- <sql>:抽取 SQL 语句标签 -->
<sql id="片段唯一标识">需要抽取的 SQL 语句</sql>

<!-- <include>:引入 SQL 片段标签 -->
<include refid="片段唯一标识 id" />

使用示例:

<!-- 抽取 sql 片段 -->
<sql id="selectStudent" select * from student</sql>

<!-- 引入 sql 片段 -->
<select id="findById" parameterType="int" resultType="student">
<include refid="selectStudent"></include> where id=#{id}
</select>

<!-- 引入 sql 片段 -->
<select id="findByIds" parameterType="list" resultType="student">
<include refid="selectStudent"></include>
<where>
<foreach collection="array" open="id in(" close=")" item="id" separator=",">
#{id}
</foreach>
</where>
</select>


分页插件

分页插件介绍

分页功能介绍:

image

  • 分页可以将很多条结果进行分页显示。
  • 如果当前在第一页,则没有上一页。如果当前在最后一页,则没有下一页。
  • 需要明确当前是第几页,这一页中显示多少条结果。

MyBatis 分页插件:

  1. 在企业级开发中,分页也是一种常见的技术。而目前使用的 MyBatis 是不带分页功能的,如果想实现分页的功能,需要我们手动编写 LIMIT 语句。但是不同的数据库实现分页的 SQL 语句也是不同的,所以手写分页的成本较高,这时就可以借助分页插件来帮助我们实现分页功能。
  2. MyBatis 可以使用第三方的插件来对功能进行扩展,如分页插件 PageHelper 就将分页的复杂操作进行了封装,使用简单的方式即可获得分页的相关数据,从而让分页功能变得非常简单。

分页插件使用

1)导入 jar 包

  • pagehelper-5.1.10.jar
  • jsqlparser-3.1.jar

2)在 Mybatis 全局配置文件中配置 PageHelper 插件

image

<!-- 注意:分页插件的配置位置需在通用 mapper 之前 -->
<plugins>
    <!-- pageHelper 4.0 版本配置
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <property name="dialect" value="mysql"/>
        </plugin>-->
    <!-- pageHelper 5.0 以上版本的配置 -->
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
    </plugin>
</plugins>

3)测试分页数据获取

import com.bean.Student;
import com.github.pagehelper.PageHelper;

import com.github.pagehelper.PageInfo;
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.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class StudentMapperTest {

<span class="hljs-keyword">private</span> SqlSessionFactory sqlSessionFactory;

<span class="hljs-meta">@Before</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setUp</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> IOException {
    <span class="hljs-comment">// 加载核心配置文件</span>
    <span class="hljs-type">InputStream</span> <span class="hljs-variable">inputStream</span> <span class="hljs-operator">=</span> Resources.getResourceAsStream(<span class="hljs-string">"MyBatisConfig.xml"</span>);
    <span class="hljs-comment">// 获取SqlSession工厂对象</span>
    sqlSessionFactory = <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(inputStream);
}

<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">testPaging</span><span class="hljs-params">()</span> {
    <span class="hljs-type">SqlSession</span> <span class="hljs-variable">sqlSession</span> <span class="hljs-operator">=</span> sqlSessionFactory.openSession();
    <span class="hljs-comment">// 由mybatis通过sqlSession来创建代理对象</span>
    <span class="hljs-comment">// 创建StudentMapper对象</span>
    <span class="hljs-type">StudentMapper</span> <span class="hljs-variable">mapper</span> <span class="hljs-operator">=</span> sqlSession.getMapper(StudentMapper.class);

    <span class="hljs-comment">// 通过分页助手来实现分页功能</span>
    <span class="hljs-comment">// 第一页:显示3条数据</span>
    <span class="hljs-comment">// PageHelper.startPage(1, 3);</span>
    <span class="hljs-comment">// 第二页:显示3条数据</span>
    <span class="hljs-comment">// PageHelper.startPage(2, 3);</span>
    <span class="hljs-comment">// 第三页:显示3条数据</span>
    PageHelper.startPage(<span class="hljs-number">3</span>, <span class="hljs-number">3</span>);

    <span class="hljs-comment">// 5.调用实现类的方法,接收结果</span>
    List&lt;Student&gt; list = mapper.selectAll();

    <span class="hljs-comment">// 6. 处理结果</span>
    <span class="hljs-keyword">for</span> (Student student : list) {
        System.out.println(student);
    }

    <span class="hljs-comment">// 获取分页的相关参数</span>
    PageInfo&lt;Student&gt; info = <span class="hljs-keyword">new</span> <span class="hljs-title class_">PageInfo</span>&lt;&gt;(list);
    System.out.println(<span class="hljs-string">"总条数:"</span> + info.getTotal());
    System.out.println(<span class="hljs-string">"总页数:"</span> + info.getPages());
    System.out.println(<span class="hljs-string">"每页显示条数:"</span> + info.getPageSize());
    System.out.println(<span class="hljs-string">"当前页数:"</span> + info.getPageNum());
    System.out.println(<span class="hljs-string">"上一页数:"</span> + info.getPrePage());
    System.out.println(<span class="hljs-string">"下一页数:"</span> + info.getNextPage());
    System.out.println(<span class="hljs-string">"是否是第一页:"</span> + info.isIsFirstPage());
    System.out.println(<span class="hljs-string">"是否是最后一页:"</span> + info.isIsLastPage());

    <span class="hljs-comment">// 关闭资源</span>
    sqlSession.close();
}

}


Mybatis 多表操作

多表模型介绍

  • 一对一:在任意一方建立外键,关联对方的主键。
  • 一对多:在多的一方建立外键,关联对方(一张表)的主键。
  • 多对多:借助中间表,中间表至少两个字段,分别关联两张表的主键。

一对一

案例:人和身份证,一个人只有一个身份证

1)SQL 数据准备:

CREATE TABLE person(
    id INT PRIMARY KEY AUTO_INCREMENT,
    NAME VARCHAR(20),
    age INT
);

INSERT INTO person VALUES (NULL, '张三', 23);
INSERT INTO person VALUES (NULL, '李四', 24);
INSERT INTO person VALUES (NULL, '王五', 25);

CREATE TABLE card(
id INT PRIMARY KEY AUTO_INCREMENT,
number VARCHAR(30),
pid INT,
CONSTRAINT cp_fk FOREIGN KEY (pid) REFERENCES person(id)
);

INSERT INTO card VALUES (NULL, '12345', 1);
INSERT INTO card VALUES (NULL, '23456', 2);
INSERT INTO card VALUES (NULL, '34567', 3);

2)实体类:

  • Person 类:
package com.bean;

public class Person {
private Integer id; // 主键 id
private String name; // 人的姓名
private Integer age; // 人的年龄

<span class="hljs-keyword">public</span> <span class="hljs-title function_">Person</span><span class="hljs-params">()</span> {
}

<span class="hljs-keyword">public</span> <span class="hljs-title function_">Person</span><span class="hljs-params">(Integer id, String name, Integer age)</span> {
    <span class="hljs-built_in">this</span>.id = id;
    <span class="hljs-built_in">this</span>.name = name;
    <span class="hljs-built_in">this</span>.age = age;
}

<span class="hljs-keyword">public</span> Integer <span class="hljs-title function_">getId</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> id;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setId</span><span class="hljs-params">(Integer id)</span> {
    <span class="hljs-built_in">this</span>.id = id;
}

<span class="hljs-keyword">public</span> String <span class="hljs-title function_">getName</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> name;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setName</span><span class="hljs-params">(String name)</span> {
    <span class="hljs-built_in">this</span>.name = name;
}

<span class="hljs-keyword">public</span> Integer <span class="hljs-title function_">getAge</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> age;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setAge</span><span class="hljs-params">(Integer age)</span> {
    <span class="hljs-built_in">this</span>.age = age;
}

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> String <span class="hljs-title function_">toString</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Person{"</span> +
            <span class="hljs-string">"id="</span> + id +
            <span class="hljs-string">", name='"</span> + name + <span class="hljs-string">'\''</span> +
            <span class="hljs-string">", age="</span> + age +
            <span class="hljs-string">'}'</span>;
}

}

  • Card 类:
package com.bean;

public class Card {
private Integer id;
private Integer number;
private Person person; // 所属人的对象

<span class="hljs-keyword">public</span> <span class="hljs-title function_">Card</span><span class="hljs-params">()</span> {
}

<span class="hljs-keyword">public</span> <span class="hljs-title function_">Card</span><span class="hljs-params">(Integer id, Integer number, Person person)</span> {
    <span class="hljs-built_in">this</span>.id = id;
    <span class="hljs-built_in">this</span>.number = number;
    <span class="hljs-built_in">this</span>.person = person;
}

<span class="hljs-keyword">public</span> Integer <span class="hljs-title function_">getId</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> id;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setId</span><span class="hljs-params">(Integer id)</span> {
    <span class="hljs-built_in">this</span>.id = id;
}

<span class="hljs-keyword">public</span> Integer <span class="hljs-title function_">getNumber</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> number;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setNumber</span><span class="hljs-params">(Integer number)</span> {
    <span class="hljs-built_in">this</span>.number = number;
}

<span class="hljs-keyword">public</span> Person <span class="hljs-title function_">getPerson</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> person;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setPerson</span><span class="hljs-params">(Person person)</span> {
    <span class="hljs-built_in">this</span>.person = person;
}

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> String <span class="hljs-title function_">toString</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Card{"</span> +
            <span class="hljs-string">"id="</span> + id +
            <span class="hljs-string">", number="</span> + number +
            <span class="hljs-string">", person="</span> + person +
            <span class="hljs-string">'}'</span>;
}

}

3)配置文件:

  • 全局配置文件:
<?xml version="1.0" encoding="UTF-8" ?>
<!--MyBatis 的 DTD 约束 -->
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">

<!--configuration 核心根标签 -->
<configuration>

<span class="hljs-comment">&lt;!--引入数据库连接的配置文件--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">properties</span> <span class="hljs-attr">resource</span>=<span class="hljs-string">"jdbc.properties"</span>/&gt;</span>

<span class="hljs-comment">&lt;!--配置LOG4J--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">settings</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">setting</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"logImpl"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"log4j"</span>/&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">settings</span>&gt;</span>

<span class="hljs-comment">&lt;!--起别名--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">typeAliases</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">package</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"com.bean"</span>/&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">typeAliases</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">plugins</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- 注意:分页插件的配置位置需在通用 mapper 之前 --&gt;</span>

<!-- <plugin interceptor="com.github.pagehelper.PageHelper">-->
<!-- &lt;!&ndash; 指定方言 &ndash;&gt;-->
<!-- <property name="dialect" value="mysql"/>-->
<!-- </plugin>-->
<plugin interceptor="com.github.pagehelper.PageInterceptor">
</plugin>
</plugins>

<span class="hljs-comment">&lt;!--environments配置数据库环境,环境可以有多个。default属性指定使用的是哪个--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">environments</span> <span class="hljs-attr">default</span>=<span class="hljs-string">"mysql"</span>&gt;</span>
    <span class="hljs-comment">&lt;!--environment配置数据库环境  id属性唯一标识--&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">environment</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"mysql"</span>&gt;</span>
        <span class="hljs-comment">&lt;!-- transactionManager事务管理。  type属性,采用JDBC默认的事务--&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">transactionManager</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"JDBC"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">transactionManager</span>&gt;</span>
        <span class="hljs-comment">&lt;!-- dataSource数据源信息   type属性 连接池--&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dataSource</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"POOLED"</span>&gt;</span>
            <span class="hljs-comment">&lt;!-- property获取数据库连接的配置信息 --&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"driver"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"${driver}"</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"url"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"${url}"</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"username"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"${username}"</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"${password}"</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dataSource</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">environment</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">environments</span>&gt;</span>

<span class="hljs-comment">&lt;!-- mappers引入映射配置文件 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">mappers</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- mapper 引入指定的映射配置文件 resource属性指定映射配置文件的名称 --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">mapper</span> <span class="hljs-attr">resource</span>=<span class="hljs-string">"TableMapper.xml"</span>/&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">mappers</span>&gt;</span>

</configuration>

  • 映射文件:
<?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.mapper.OneToOneMapper">
<!-- 配置字段和实体对象属性的映射关系 -->
<!-- 使用 resultMap 来进行一对一结果映射,它是将关联对象添加到主信息的对象中,具体说是对象嵌套对象的一种映射方式 -->
<resultMap id="oneToOne" type="card">
<!-- id 标签:建议在关联查询时必须写上,不写不会报错,但是会影响性能 -->
<id column="cid" property="id" />
<result column="number" property="number" />
<!--
association:配置被包含对象的映射关系
property:被包含对象的变量名
javaType:被包含对象的数据类型
-->

<association property="person" javaType="person">
<id column="pid" property="id" />
<result column="name" property="name" />
<result column="age" property="age" />
</association>
</resultMap>

<span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"selectAll"</span> <span class="hljs-attr">resultMap</span>=<span class="hljs-string">"oneToOne"</span>&gt;</span>
    SELECT c.id cid, number, pid, NAME, age FROM card c, person p WHERE c.pid = p.id
<span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span>

</mapper>

4)Mapper 接口类:

import com.bean.Card;

import java.util.List;

public interface OneToOneMapper {

<span class="hljs-comment">// 查询全部</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> List&lt;Card&gt; <span class="hljs-title function_">selectAll</span><span class="hljs-params">()</span>;

}

5)测试类:

import com.bean.Card;
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.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class OneToOneTest {

<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">testSelectAll</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> IOException {
    <span class="hljs-comment">// 1.加载核心配置文件</span>
    <span class="hljs-type">InputStream</span> <span class="hljs-variable">is</span> <span class="hljs-operator">=</span> Resources.getResourceAsStream(<span class="hljs-string">"MyBatisConfig.xml"</span>);

    <span class="hljs-comment">// 2.获取SqlSession工厂对象</span>
    <span class="hljs-type">SqlSessionFactory</span> <span class="hljs-variable">sqlSessionFactory</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(is);

    <span class="hljs-comment">// 3.通过工厂对象获取SqlSession对象</span>
    <span class="hljs-type">SqlSession</span> <span class="hljs-variable">sqlSession</span> <span class="hljs-operator">=</span> sqlSessionFactory.openSession(<span class="hljs-literal">true</span>);

    <span class="hljs-comment">// 4.获取OneToOneMapper接口的实现类对象</span>
    <span class="hljs-type">OneToOneMapper</span> <span class="hljs-variable">mapper</span> <span class="hljs-operator">=</span> sqlSession.getMapper(OneToOneMapper.class);

    <span class="hljs-comment">// 5.调用实现类的方法,接收结果</span>
    List&lt;Card&gt; list = mapper.selectAll();

    <span class="hljs-comment">// 6.处理结果</span>
    <span class="hljs-keyword">for</span> (Card c : list) {
        System.out.println(c);
    }

    <span class="hljs-comment">// 7.释放资源</span>
    sqlSession.close();
    is.close();
}

}

一对多

案例:班级和学生,一个班级可以有多个学生

1)SQL 准备:

CREATE TABLE classes(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(20)
);
INSERT INTO classes VALUES (NULL,'一班');
INSERT INTO classes VALUES (NULL,'二班');

CREATE TABLE student(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(30),
age INT,
cid INT,
CONSTRAINT cs_fk FOREIGN KEY (cid) REFERENCES classes(id)
);
INSERT INTO student VALUES (NULL,'张三',23,1);
INSERT INTO student VALUES (NULL,'李四',24,1);
INSERT INTO student VALUES (NULL,'王五',25,2);
INSERT INTO student VALUES (NULL,'赵六',26,2);

2)实体类:

  • 班级类:
package com.bean;

import java.util.List;

public class Classes {

<span class="hljs-keyword">private</span> Integer id;     <span class="hljs-comment">// 主键id</span>
<span class="hljs-keyword">private</span> String name;    <span class="hljs-comment">// 班级名称</span>
<span class="hljs-keyword">private</span> List&lt;Student&gt; students;  <span class="hljs-comment">// 班级中所有学生对象</span>

<span class="hljs-keyword">public</span> <span class="hljs-title function_">Classes</span><span class="hljs-params">()</span> {
}

<span class="hljs-keyword">public</span> <span class="hljs-title function_">Classes</span><span class="hljs-params">(Integer id, String name, List&lt;Student&gt; students)</span> {
    <span class="hljs-built_in">this</span>.id = id;
    <span class="hljs-built_in">this</span>.name = name;
    <span class="hljs-built_in">this</span>.students = students;
}

<span class="hljs-keyword">public</span> Integer <span class="hljs-title function_">getId</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> id;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setId</span><span class="hljs-params">(Integer id)</span> {
    <span class="hljs-built_in">this</span>.id = id;
}

<span class="hljs-keyword">public</span> String <span class="hljs-title function_">getName</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> name;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setName</span><span class="hljs-params">(String name)</span> {
    <span class="hljs-built_in">this</span>.name = name;
}

<span class="hljs-keyword">public</span> List&lt;Student&gt; <span class="hljs-title function_">getStudents</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> students;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setStudents</span><span class="hljs-params">(List&lt;Student&gt; students)</span> {
    <span class="hljs-built_in">this</span>.students = students;
}

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> String <span class="hljs-title function_">toString</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Classes{"</span> +
            <span class="hljs-string">"id="</span> + id +
            <span class="hljs-string">", name='"</span> + name + <span class="hljs-string">'\''</span> +
            <span class="hljs-string">", students="</span> + students +
            <span class="hljs-string">'}'</span>;
}

}

  • 学生类:
package com.bean;

import java.util.List;

public class Student {

<span class="hljs-keyword">private</span> Integer id;  <span class="hljs-comment">// 主键id</span>
<span class="hljs-keyword">private</span> String name;  <span class="hljs-comment">// 学生姓名</span>
<span class="hljs-keyword">private</span> Integer age;  <span class="hljs-comment">// 学生年龄</span>
<span class="hljs-keyword">private</span> Classes classes;  <span class="hljs-comment">// 课程</span>

<span class="hljs-keyword">public</span> <span class="hljs-title function_">Student</span><span class="hljs-params">()</span> {
}

<span class="hljs-keyword">public</span> <span class="hljs-title function_">Student</span><span class="hljs-params">(Integer id, String name, Integer age, Classes classes)</span> {
    <span class="hljs-built_in">this</span>.id = id;
    <span class="hljs-built_in">this</span>.name = name;
    <span class="hljs-built_in">this</span>.age = age;
    <span class="hljs-built_in">this</span>.classes = classes;
}

<span class="hljs-keyword">public</span> Classes <span class="hljs-title function_">getClasses</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> classes;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setClasses</span><span class="hljs-params">(Classes classes)</span> {
    <span class="hljs-built_in">this</span>.classes = classes;
}

<span class="hljs-keyword">public</span> Integer <span class="hljs-title function_">getId</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> id;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setId</span><span class="hljs-params">(Integer id)</span> {
    <span class="hljs-built_in">this</span>.id = id;
}

<span class="hljs-keyword">public</span> String <span class="hljs-title function_">getName</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> name;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setName</span><span class="hljs-params">(String name)</span> {
    <span class="hljs-built_in">this</span>.name = name;
}

<span class="hljs-keyword">public</span> Integer <span class="hljs-title function_">getAge</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> age;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setAge</span><span class="hljs-params">(Integer age)</span> {
    <span class="hljs-built_in">this</span>.age = age;
}

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> String <span class="hljs-title function_">toString</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Student{"</span> +
            <span class="hljs-string">"id="</span> + id +
            <span class="hljs-string">", name='"</span> + name + <span class="hljs-string">'\''</span> +
            <span class="hljs-string">", age="</span> + age +
            <span class="hljs-string">", classes="</span> + classes +
            <span class="hljs-string">'}'</span>;
}

}

3)映射文件:

<?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.mapper.OneToManyMapper">
<resultMap id="oneToMany" type="classes">
<id column="cid" property="id"/>
<result column="cname" property="name"/>

    <span class="hljs-comment">&lt;!--
        collection:配置被包含的集合对象映射关系
        property:被包含对象的变量名
        ofType:被包含对象的实际数据类型
    --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">collection</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"students"</span> <span class="hljs-attr">ofType</span>=<span class="hljs-string">"student"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">id</span> <span class="hljs-attr">column</span>=<span class="hljs-string">"sid"</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"id"</span>/&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">result</span> <span class="hljs-attr">column</span>=<span class="hljs-string">"sname"</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"name"</span>/&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">result</span> <span class="hljs-attr">column</span>=<span class="hljs-string">"sage"</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"age"</span>/&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">collection</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">resultMap</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"selectAll"</span> <span class="hljs-attr">resultMap</span>=<span class="hljs-string">"oneToMany"</span>&gt;</span>
    SELECT c.id cid, c.name cname, s.id sid, s.name sname, s.age sage FROM classes c, student s WHERE c.id=s.cid
<span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span>

</mapper>

4)Mapper 接口:

import com.bean.Classes;

import java.util.List;

public interface OneToManyMapper {

<span class="hljs-comment">// 查询全部</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> List&lt;Classes&gt; <span class="hljs-title function_">selectAll</span><span class="hljs-params">()</span>;

}

5)测试类:

package com.mapper;

import com.bean.Classes;
import com.bean.Student;
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.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class OneToManyTest {
@Test
public void testSelectAll() throws IOException {
// 1. 加载核心配置文件
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");

    <span class="hljs-comment">// 2.获取SqlSession工厂对象</span>
    <span class="hljs-type">SqlSessionFactory</span> <span class="hljs-variable">sqlSessionFactory</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(is);

    <span class="hljs-comment">// 3.通过工厂对象获取SqlSession对象</span>
    <span class="hljs-type">SqlSession</span> <span class="hljs-variable">sqlSession</span> <span class="hljs-operator">=</span> sqlSessionFactory.openSession(<span class="hljs-literal">true</span>);

    <span class="hljs-comment">// 4.获取OneToOneMapper接口的实现类对象</span>
    <span class="hljs-type">OneToManyMapper</span> <span class="hljs-variable">mapper</span> <span class="hljs-operator">=</span> sqlSession.getMapper(OneToManyMapper.class);

    <span class="hljs-comment">// 5.调用实现类的方法,接收结果</span>
    List&lt;Classes&gt; classes = mapper.selectAll();

    <span class="hljs-comment">// 6.处理结果</span>
    <span class="hljs-keyword">for</span> (Classes cls : classes) {
        System.out.println(cls.getId() + <span class="hljs-string">","</span> + cls.getName());
        List&lt;Student&gt; students = cls.getStudents();
        <span class="hljs-keyword">for</span> (Student student : students) {
            System.out.println(<span class="hljs-string">"\t"</span> + student);
        }
    }

    <span class="hljs-comment">// 7.释放资源</span>
    sqlSession.close();
    is.close();
}

}

多对多

案例:学生和课程,一个学生可以选择多门课程、一个课程也可以被多个学生所选择

1)SQL 准备:

CREATE TABLE course(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(20)
);
INSERT INTO course VALUES (NULL,'语文');
INSERT INTO course VALUES (NULL,'数学');

CREATE TABLE student_course(
id INT PRIMARY KEY AUTO_INCREMENT,
sid INT,
cid INT,
CONSTRAINT sc_fk1 FOREIGN KEY (sid) REFERENCES student(id),
CONSTRAINT sc_fk2 FOREIGN KEY (cid) REFERENCES course(id)
);

INSERT INTO student_course VALUES (NULL,1,1);
INSERT INTO student_course VALUES (NULL,1,2);
INSERT INTO student_course VALUES (NULL,2,1);
INSERT INTO student_course VALUES (NULL,2,2);

2)实体类:

  • 学生类:
import java.util.List;

public class Student {
private Integer id; // 主键 id
private String name; // 学生姓名
private Integer age; // 学生年龄

<span class="hljs-keyword">private</span> List&lt;Course&gt; courses;   <span class="hljs-comment">// 学生所选择的课程集合</span>

<span class="hljs-keyword">public</span> <span class="hljs-title function_">Student</span><span class="hljs-params">()</span> {
}

<span class="hljs-keyword">public</span> <span class="hljs-title function_">Student</span><span class="hljs-params">(Integer id, String name, Integer age, List&lt;Course&gt; courses)</span> {
    <span class="hljs-built_in">this</span>.id = id;
    <span class="hljs-built_in">this</span>.name = name;
    <span class="hljs-built_in">this</span>.age = age;
    <span class="hljs-built_in">this</span>.courses = courses;
}

<span class="hljs-keyword">public</span> List&lt;Course&gt; <span class="hljs-title function_">getCourses</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> courses;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setCourses</span><span class="hljs-params">(List&lt;Course&gt; courses)</span> {
    <span class="hljs-built_in">this</span>.courses = courses;
}

<span class="hljs-keyword">public</span> Integer <span class="hljs-title function_">getId</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> id;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setId</span><span class="hljs-params">(Integer id)</span> {
    <span class="hljs-built_in">this</span>.id = id;
}

<span class="hljs-keyword">public</span> String <span class="hljs-title function_">getName</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> name;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setName</span><span class="hljs-params">(String name)</span> {
    <span class="hljs-built_in">this</span>.name = name;
}

<span class="hljs-keyword">public</span> Integer <span class="hljs-title function_">getAge</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> age;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setAge</span><span class="hljs-params">(Integer age)</span> {
    <span class="hljs-built_in">this</span>.age = age;
}

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> String <span class="hljs-title function_">toString</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Student{"</span> +
            <span class="hljs-string">"id="</span> + id +
            <span class="hljs-string">", name='"</span> + name + <span class="hljs-string">'\''</span> +
            <span class="hljs-string">", age="</span> + age +
            <span class="hljs-string">'}'</span>;
}

}

  • 课程类:
public class Course {
    private Integer id;   // 主键 id
    private String name;  // 课程名称
<span class="hljs-keyword">public</span> <span class="hljs-title function_">Course</span><span class="hljs-params">()</span> {
}

<span class="hljs-keyword">public</span> <span class="hljs-title function_">Course</span><span class="hljs-params">(Integer id, String name)</span> {
    <span class="hljs-built_in">this</span>.id = id;
    <span class="hljs-built_in">this</span>.name = name;
}

<span class="hljs-keyword">public</span> Integer <span class="hljs-title function_">getId</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> id;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setId</span><span class="hljs-params">(Integer id)</span> {
    <span class="hljs-built_in">this</span>.id = id;
}

<span class="hljs-keyword">public</span> String <span class="hljs-title function_">getName</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> name;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setName</span><span class="hljs-params">(String name)</span> {
    <span class="hljs-built_in">this</span>.name = name;
}

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> String <span class="hljs-title function_">toString</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Course{"</span> +
            <span class="hljs-string">"id="</span> + id +
            <span class="hljs-string">", name='"</span> + name + <span class="hljs-string">'\''</span> +
            <span class="hljs-string">'}'</span>;
}

}

3)映射文件:

<?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.mapper.ManyToManyMapper">
<resultMap id="manyToMany" type="student">
<id column="sid" property="id"/>
<result column="sname" property="name"/>
<result column="sage" property="age"/>

    <span class="hljs-tag">&lt;<span class="hljs-name">collection</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"courses"</span> <span class="hljs-attr">ofType</span>=<span class="hljs-string">"course"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">id</span> <span class="hljs-attr">column</span>=<span class="hljs-string">"cid"</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"id"</span>/&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">result</span> <span class="hljs-attr">column</span>=<span class="hljs-string">"cname"</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"name"</span>/&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">collection</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">resultMap</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"selectAll"</span> <span class="hljs-attr">resultMap</span>=<span class="hljs-string">"manyToMany"</span>&gt;</span>
    SELECT sc.sid, s.name sname, s.age sage, sc.cid, c.name cname 
    FROM student s, course c, student_course sc 
    WHERE sc.sid=s.id AND sc.cid=c.id
<span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span>

</mapper>

4)Mapper 接口:

import com.bean.Student;

import java.util.List;

public interface ManyToManyMapper {

<span class="hljs-comment">// 查询全部</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> List&lt;Student&gt; <span class="hljs-title function_">selectAll</span><span class="hljs-params">()</span>;

}

5)测试类:

package com.mapper;

import com.bean.Classes;
import com.bean.Course;
import com.bean.Student;
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.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class ManyToManyTest {
@Test
public void testSelectAll() throws IOException {
// 1. 加载核心配置文件
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");

    <span class="hljs-comment">// 2.获取SqlSession工厂对象</span>
    <span class="hljs-type">SqlSessionFactory</span> <span class="hljs-variable">sqlSessionFactory</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(is);

    <span class="hljs-comment">// 3.通过工厂对象获取SqlSession对象</span>
    <span class="hljs-type">SqlSession</span> <span class="hljs-variable">sqlSession</span> <span class="hljs-operator">=</span> sqlSessionFactory.openSession(<span class="hljs-literal">true</span>);

    <span class="hljs-comment">// 4.获取OneToOneMapper接口的实现类对象</span>
    <span class="hljs-type">ManyToManyMapper</span> <span class="hljs-variable">mapper</span> <span class="hljs-operator">=</span> sqlSession.getMapper(ManyToManyMapper.class);

    <span class="hljs-comment">//5.调用实现类的方法,接收结果</span>
    List&lt;Student&gt; students = mapper.selectAll();

    <span class="hljs-comment">//6.处理结果</span>
    <span class="hljs-keyword">for</span> (Student student : students) {
        System.out.println(student.getId() + <span class="hljs-string">","</span> + student.getName() + <span class="hljs-string">","</span> + student.getAge());
        List&lt;Course&gt; courses = student.getCourses();
        <span class="hljs-keyword">for</span> (Course cours : courses) {
            System.out.println(<span class="hljs-string">"\t"</span> + cours);
        }
    }

    <span class="hljs-comment">// 7.释放资源</span>
    sqlSession.close();
    is.close();
}

}


Mybatis 注解开发

常用注解与案例

近几年来,注解开发越来越流行,Mybatis 也可以使用注解开发方式,这样我们就可以减少编写 Mapper 映射文件了。

  • @Insert:实现新增
  • @Update:实现更新
  • @Delete:实现删除
  • @Select:实现查询
  • @Result:实现结果集的封装
  • @Results:可以与 @Result 一起使用,以封装多个结果集
  • @One:实现一对一结果集封装
  • @Many:实现一对多结果集封装

案例:student 表的 CRUD

  1. 创建 Mapper 接口:
package com.mapper;

import com.bean.Student;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import java.util.List;

public interface StudentMapper {
// 查询全部
@Select("SELECT * FROM student")
public abstract List<Student> selectAll();

<span class="hljs-comment">//新增操作</span>
<span class="hljs-meta">@Insert("INSERT INTO student VALUES (#{id},#{name},#{age})")</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> Integer <span class="hljs-title function_">insert</span><span class="hljs-params">(Student stu)</span>;

<span class="hljs-comment">//修改操作</span>
<span class="hljs-meta">@Update("UPDATE student SET name=#{name},age=#{age} WHERE id=#{id}")</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> Integer <span class="hljs-title function_">update</span><span class="hljs-params">(Student stu)</span>;

<span class="hljs-comment">//删除操作</span>
<span class="hljs-meta">@Delete("DELETE FROM student WHERE id=#{id}")</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> Integer <span class="hljs-title function_">delete</span><span class="hljs-params">(Integer id)</span>;

}

  1. 修改 Mybatis 全局配置文件:
    <mappers>
        <!-- 扫描使用注解的类 -->
        <mapper class="com.itheima.mapper.UserMapper">
    </mappers>

或者:

    <mappers>
        <!-- 扫描使用注解的类所在的包 -->
        <package name="com.mapper"></package>
    </mappers>
  1. 测试类:
package com.mapper;

import com.bean.Student;
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.jupiter.api.Test;

import java.io.InputStream;
import java.util.List;

public class AnnotationTest {

<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">selectAll</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> Exception{
    <span class="hljs-comment">//1.加载核心配置文件</span>
    <span class="hljs-type">InputStream</span> <span class="hljs-variable">is</span> <span class="hljs-operator">=</span> Resources.getResourceAsStream(<span class="hljs-string">"MyBatisConfig.xml"</span>);

    <span class="hljs-comment">//2.获取SqlSession工厂对象</span>
    <span class="hljs-type">SqlSessionFactory</span> <span class="hljs-variable">sqlSessionFactory</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(is);

    <span class="hljs-comment">//3.通过工厂对象获取SqlSession对象</span>
    <span class="hljs-type">SqlSession</span> <span class="hljs-variable">sqlSession</span> <span class="hljs-operator">=</span> sqlSessionFactory.openSession(<span class="hljs-literal">true</span>);

    <span class="hljs-comment">//4.获取StudentMapper接口的实现类对象</span>
    <span class="hljs-type">StudentMapper</span> <span class="hljs-variable">mapper</span> <span class="hljs-operator">=</span> sqlSession.getMapper(StudentMapper.class);

    <span class="hljs-comment">//5.调用实现类对象中的方法,接收结果</span>
    List&lt;Student&gt; list = mapper.selectAll();

    <span class="hljs-comment">//6.处理结果</span>
    <span class="hljs-keyword">for</span> (Student student : list) {
        System.out.println(student);
    }

    <span class="hljs-comment">//7.释放资源</span>
    sqlSession.close();
    is.close();
}

<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">insert</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> Exception{
    <span class="hljs-comment">//1.加载核心配置文件</span>
    <span class="hljs-type">InputStream</span> <span class="hljs-variable">is</span> <span class="hljs-operator">=</span> Resources.getResourceAsStream(<span class="hljs-string">"MyBatisConfig.xml"</span>);

    <span class="hljs-comment">//2.获取SqlSession工厂对象</span>
    <span class="hljs-type">SqlSessionFactory</span> <span class="hljs-variable">sqlSessionFactory</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(is);

    <span class="hljs-comment">//3.通过工厂对象获取SqlSession对象</span>
    <span class="hljs-type">SqlSession</span> <span class="hljs-variable">sqlSession</span> <span class="hljs-operator">=</span> sqlSessionFactory.openSession(<span class="hljs-literal">true</span>);

    <span class="hljs-comment">//4.获取StudentMapper接口的实现类对象</span>
    <span class="hljs-type">StudentMapper</span> <span class="hljs-variable">mapper</span> <span class="hljs-operator">=</span> sqlSession.getMapper(StudentMapper.class);

    <span class="hljs-comment">//5.调用实现类对象中的方法,接收结果</span>
    <span class="hljs-type">Student</span> <span class="hljs-variable">stu</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Student</span>(<span class="hljs-number">4</span>, <span class="hljs-string">"赵六"</span>, <span class="hljs-number">26</span>);
    <span class="hljs-type">Integer</span> <span class="hljs-variable">result</span> <span class="hljs-operator">=</span> mapper.insert(stu);

    <span class="hljs-comment">//6.处理结果</span>
    System.out.println(result);

    <span class="hljs-comment">//7.释放资源</span>
    sqlSession.close();
    is.close();
}

<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">update</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> Exception{
    <span class="hljs-comment">//1.加载核心配置文件</span>
    <span class="hljs-type">InputStream</span> <span class="hljs-variable">is</span> <span class="hljs-operator">=</span> Resources.getResourceAsStream(<span class="hljs-string">"MyBatisConfig.xml"</span>);

    <span class="hljs-comment">//2.获取SqlSession工厂对象</span>
    <span class="hljs-type">SqlSessionFactory</span> <span class="hljs-variable">sqlSessionFactory</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(is);

    <span class="hljs-comment">//3.通过工厂对象获取SqlSession对象</span>
    <span class="hljs-type">SqlSession</span> <span class="hljs-variable">sqlSession</span> <span class="hljs-operator">=</span> sqlSessionFactory.openSession(<span class="hljs-literal">true</span>);

    <span class="hljs-comment">//4.获取StudentMapper接口的实现类对象</span>
    <span class="hljs-type">StudentMapper</span> <span class="hljs-variable">mapper</span> <span class="hljs-operator">=</span> sqlSession.getMapper(StudentMapper.class);

    <span class="hljs-comment">//5.调用实现类对象中的方法,接收结果</span>
    <span class="hljs-type">Student</span> <span class="hljs-variable">stu</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Student</span>(<span class="hljs-number">4</span>, <span class="hljs-string">"赵六"</span>, <span class="hljs-number">36</span>);
    <span class="hljs-type">Integer</span> <span class="hljs-variable">result</span> <span class="hljs-operator">=</span> mapper.update(stu);

    <span class="hljs-comment">//6.处理结果</span>
    System.out.println(result);

    <span class="hljs-comment">//7.释放资源</span>
    sqlSession.close();
    is.close();
}

<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">delete</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> Exception{
    <span class="hljs-comment">//1.加载核心配置文件</span>
    <span class="hljs-type">InputStream</span> <span class="hljs-variable">is</span> <span class="hljs-operator">=</span> Resources.getResourceAsStream(<span class="hljs-string">"MyBatisConfig.xml"</span>);

    <span class="hljs-comment">//2.获取SqlSession工厂对象</span>
    <span class="hljs-type">SqlSessionFactory</span> <span class="hljs-variable">sqlSessionFactory</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(is);

    <span class="hljs-comment">//3.通过工厂对象获取SqlSession对象</span>
    <span class="hljs-type">SqlSession</span> <span class="hljs-variable">sqlSession</span> <span class="hljs-operator">=</span> sqlSessionFactory.openSession(<span class="hljs-literal">true</span>);

    <span class="hljs-comment">//4.获取StudentMapper接口的实现类对象</span>
    <span class="hljs-type">StudentMapper</span> <span class="hljs-variable">mapper</span> <span class="hljs-operator">=</span> sqlSession.getMapper(StudentMapper.class);

    <span class="hljs-comment">//5.调用实现类对象中的方法,接收结果</span>
    <span class="hljs-type">Integer</span> <span class="hljs-variable">result</span> <span class="hljs-operator">=</span> mapper.delete(<span class="hljs-number">4</span>);

    <span class="hljs-comment">//6.处理结果</span>
    System.out.println(result);

    <span class="hljs-comment">//7.释放资源</span>
    sqlSession.close();
    is.close();
}

}


MyBatis 注解开发的多表操作

实现复杂关系映射之前我们可以在映射文件中通过配置 <resultMap> 来实现,使用注解开发后,我们可以使用 @Results、@Result、@One、@Many 注解组合来完成复杂关系的配置。

image

image

一对一查询

需求:查询一个用户信息,与此同时查询出该用户对应的身份证信息

image

1)对应 SQL:

SELECT * FROM card;

SELECT * FROM person WHERE id=#{id};

2)创建 PersonMapper 接口:

import com.bean.Person;
import org.apache.ibatis.annotations.Select;

public interface PersonMapper {
// 根据 id 查询
@Select("SELECT * FROM person WHERE id=#{id}")
public abstract Person selectById(Integer id);
}

3)使用注解配置 CardMapper:

import com.bean.Card;
import com.bean.Person;
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface CardMapper {
// 查询全部
@Select("SELECT * FROM card")
@Results({
@Result(column="id", property="id"), // id 列
@Result(column="number", property="number"), // number 列
@Result( // Card 表中的 person id 列
property = "person", // 被包含对象的变量名
javaType = Person.class, // 被包含对象的实际数据类型
column = "pid", // 根据查询出的 card 表中的 pid 字段来查询 person 表
/*
one、@One 一对一固定写法
select 属性:指定调用哪个接口中的哪个方法
*/
one = @One(select="com.mapper.PersonMapper.selectById")
)
})

public abstract List<Card> selectAll();
}

4)测试类:

import com.bean.Card;
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.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class OneToOneTest {

<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">testSelectAll</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> IOException {
    <span class="hljs-comment">// 1.加载核心配置文件</span>
    <span class="hljs-type">InputStream</span> <span class="hljs-variable">is</span> <span class="hljs-operator">=</span> Resources.getResourceAsStream(<span class="hljs-string">"MyBatisConfig.xml"</span>);

    <span class="hljs-comment">// 2.获取SqlSession工厂对象</span>
    <span class="hljs-type">SqlSessionFactory</span> <span class="hljs-variable">sqlSessionFactory</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(is);

    <span class="hljs-comment">// 3.通过工厂对象获取SqlSession对象</span>
    <span class="hljs-type">SqlSession</span> <span class="hljs-variable">sqlSession</span> <span class="hljs-operator">=</span> sqlSessionFactory.openSession(<span class="hljs-literal">true</span>);

    <span class="hljs-comment">// 4.获取OneToOneMapper接口的实现类对象</span>
    <span class="hljs-type">CardMapper</span> <span class="hljs-variable">mapper</span> <span class="hljs-operator">=</span> sqlSession.getMapper(CardMapper.class);

    <span class="hljs-comment">// 5.调用实现类的方法,接收结果</span>
    List&lt;Card&gt; list = mapper.selectAll();

    <span class="hljs-comment">// 6.处理结果</span>
    <span class="hljs-keyword">for</span> (Card c : list) {
        System.out.println(c);
    }

    <span class="hljs-comment">// 7.释放资源</span>
    sqlSession.close();
    is.close();
}

}

执行结果:

Card{id=1, number=12345, person=Person{id=1, name='张三', age=23}}
Card{id=2, number=23456, person=Person{id=2, name='李四', age=24}}
Card{id=3, number=34567, person=Person{id=3, name='王五', age=25}}

一对多

需求:查询一个课程,与此同时查询出该课程对应的学生信息

image

1)对应的 SQL:

SELECT * FROM classes

SELECT * FROM student WHERE cid=#{cid}

2)创建 StudentMapper 接口:

import com.bean.Student;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface StudentMapper {
// 根据 cid 查询 student 表
@Select("SELECT * FROM student WHERE cid=#{cid}")
public abstract List<Student> selectByCid(Integer cid);
}

3)使用注解配置 CardMapper:

package com.mapper;

import com.bean.Card;
import com.bean.Person;
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface CardMapper {
// 查询全部
@Select("SELECT * FROM card")
@Results({
@Result(column="id", property="id"), // id 列
@Result(column="number", property="number"), // number 列
@Result( // Card 表中的 person id 列
property = "person", // 被包含对象的变量名
javaType = Person.class, // 被包含对象的实际数据类型
column = "pid", // 根据查询出的 card 表中的 pid 字段来查询 person 表
/*
one、@One 一对一固定写法
select 属性:指定调用哪个接口中的哪个方法
*/
one = @One(select="com.mapper.PersonMapper.selectById")
)
})

public abstract List<Card> selectAll();
}

4)测试类:

package com.mapper;

import com.bean.Classes;
import com.bean.Student;
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.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class OneToManyTest {
@Test
public void testSelectAll() throws IOException {
// 1. 加载核心配置文件
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");

    <span class="hljs-comment">// 2.获取SqlSession工厂对象</span>
    <span class="hljs-type">SqlSessionFactory</span> <span class="hljs-variable">sqlSessionFactory</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(is);

    <span class="hljs-comment">// 3.通过工厂对象获取SqlSession对象</span>
    <span class="hljs-type">SqlSession</span> <span class="hljs-variable">sqlSession</span> <span class="hljs-operator">=</span> sqlSessionFactory.openSession(<span class="hljs-literal">true</span>);

    <span class="hljs-comment">// 4.获取OneToOneMapper接口的实现类对象</span>
    <span class="hljs-type">ClassesMapper</span> <span class="hljs-variable">mapper</span> <span class="hljs-operator">=</span> sqlSession.getMapper(ClassesMapper.class);

    <span class="hljs-comment">// 5.调用实现类的方法,接收结果</span>
    List&lt;Classes&gt; classes = mapper.selectAll();

    <span class="hljs-comment">// 6.处理结果</span>
    <span class="hljs-keyword">for</span> (Classes cls : classes) {
        System.out.println(cls.getId() + <span class="hljs-string">","</span> + cls.getName());
        List&lt;Student&gt; students = cls.getStudents();
        <span class="hljs-keyword">for</span> (Student student : students) {
            System.out.println(<span class="hljs-string">"\t"</span> + student);
        }
    }

    <span class="hljs-comment">// 7.释放资源</span>
    sqlSession.close();
    is.close();
}

}

执行结果:

1,一班
	Student{id=1, name='张三', age=23}
	Student{id=2, name='李四', age=24}
2,二班
	Student{id=3, name='王五', age=25}

多对多

需求:查询学生以及所对应的课程信息

image

1)对应的 SQL:

SELECT DISTINCT s.id,s.name,s.age FROM student s,stu_cr sc WHERE sc.sid=s.id
SELECT c.id,c.name FROM stu_cr sc,course c WHERE sc.cid=c.id AND sc.sid=#{id}

2)创建 CourseMapper 接口:

import com.bean.Course;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface CourseMapper {
// 根据学生 id 查询所选课程
@Select("SELECT c.id, c.name FROM stu_cr sc, course c WHERE sc.cid=c.id AND sc.sid=#{id}")
public abstract List<Course> selectBySid(Integer id);
}

3)使用注解配置 StudentMapper 接口:

package com.mapper;

import com.bean.Student;
import org.apache.ibatis.annotations.Many;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface StudentMapper {
// 查询全部
@Select("SELECT DISTINCT s.id,s.name,s.age FROM student s,stu_cr sc WHERE sc.sid=s.id")
@Results({
@Result(column="id", property="id"),
@Result(column="name", property="name"),
@Result(column="age", property="age"),
@Result(
property="courses", // 被包含对象的变量名
javaType=List.class, // 被包含对象的实际数据类型
column="id", // 根据查询出 student 表的 id 来作为关联条件,去查询中间表和课程表
/*
many、@Many 一对多查询的固定写法
select 属性:指定调用哪个接口中的哪个查询方法
*/
many = @Many(select="com.mapper.CourseMapper.selectBySid")
)
})

public abstract List<Student> selectAll();
}

4)测试类:

package com.mapper;

import com.bean.Classes;
import com.bean.Course;
import com.bean.Student;
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.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class ManyToManyTest {
@Test
public void testSelectAll() throws IOException {
// 1. 加载核心配置文件
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");

    <span class="hljs-comment">// 2.获取SqlSession工厂对象</span>
    <span class="hljs-type">SqlSessionFactory</span> <span class="hljs-variable">sqlSessionFactory</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(is);

    <span class="hljs-comment">// 3.通过工厂对象获取SqlSession对象</span>
    <span class="hljs-type">SqlSession</span> <span class="hljs-variable">sqlSession</span> <span class="hljs-operator">=</span> sqlSessionFactory.openSession(<span class="hljs-literal">true</span>);

    <span class="hljs-comment">// 4.获取OneToOneMapper接口的实现类对象</span>
    <span class="hljs-type">StudentMapper</span> <span class="hljs-variable">mapper</span> <span class="hljs-operator">=</span> sqlSession.getMapper(StudentMapper.class);

    <span class="hljs-comment">// 5.调用实现类对象中的方法,接收结果</span>
    List&lt;Student&gt; list = mapper.selectAll();

    <span class="hljs-comment">// 6.处理结果</span>
    <span class="hljs-keyword">for</span> (Student student : list) {
        System.out.println(student.getId() + <span class="hljs-string">","</span> + student.getName() + <span class="hljs-string">","</span> + student.getAge());
        List&lt;Course&gt; courses = student.getCourses();
        <span class="hljs-keyword">for</span> (Course cours : courses) {
            System.out.println(<span class="hljs-string">"\t"</span> + cours);
        }
    }

    <span class="hljs-comment">// 7.释放资源</span>
    sqlSession.close();
    is.close();
}

}

执行结果:

1,张三,23
	Course{id=1, name='语文'}
	Course{id=2, name='数学'}
2,李四,24
	Course{id=1, name='语文'}
	Course{id=2, name='数学'}

构建 SQL

之前在通过注解开发时,相关 SQL 语句都是自己直接拼写的,一些关键字写起来比较麻烦、而且容易出错。因此,MyBatis 给我们提供了 org.apache.ibatis.jdbc.SQL 功能类,专门用于构建 SQL 语句。

image

查询功能的实现:

  • 定义功能类并提供获取查询的 SQL 语句的方法。
  • @SelectProvider:生成查询用的 SQL 语句注解。
    • type 属性:生成 SQL 语句功能类对象
    • method 属性:指定调用方法

新增功能的实现:

  • 定义功能类并提供获取新增的 SQL 语句的方法。
  • @InsertProvider:生成新增用的 SQL 语句注解。
    • type 属性:生成 SQL 语句功能类对象
    • method 属性:指定调用方法

修改功能的实现:

  • 定义功能类并提供获取修改的 SQL 语句的方法。
  • @UpdateProvider:生成修改用的 SQL 语句注解。
    • type 属性:生成 SQL 语句功能类对象
    • method 属性:指定调用方法

删除功能的实现:

  • 定义功能类并提供获取删除的 SQL 语句的方法。
  • @DeleteProvider:生成删除用的 SQL 语句注解。
    • type 属性:生成 SQL 语句功能类对象
    • method 属性:指定调用方法

案例:

  • Dao 层:
import com.itheima.domain.Student;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import java.util.ArrayList;

/*
Dao 层接口
*/

public interface StudentDao {
// 查询所有学生信息
@Select("SELECT * FROM student")
public abstract ArrayList<Student> findAll();

<span class="hljs-comment">//条件查询,根据id获取学生信息</span>
<span class="hljs-meta">@Select("SELECT * FROM student WHERE sid=#{sid}")</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> Student <span class="hljs-title function_">findById</span><span class="hljs-params">(Integer sid)</span>;

<span class="hljs-comment">//新增学生信息</span>
<span class="hljs-meta">@Insert("INSERT INTO student VALUES (#{sid},#{name},#{age},#{birthday})")</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-type">int</span> <span class="hljs-title function_">insert</span><span class="hljs-params">(Student stu)</span>;

<span class="hljs-comment">//修改学生信息</span>
<span class="hljs-meta">@Update("UPDATE student SET name=#{name},age=#{age},birthday=#{birthday} WHERE sid=#{sid}")</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-type">int</span> <span class="hljs-title function_">update</span><span class="hljs-params">(Student stu)</span>;

<span class="hljs-comment">//删除学生信息</span>
<span class="hljs-meta">@Delete("DELETE FROM student WHERE sid=#{sid}")</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-type">int</span> <span class="hljs-title function_">delete</span><span class="hljs-params">(Integer sid)</span>;

}

  • Dao 实现类:
import com.itheima.dao.StudentDao;
import com.itheima.domain.Student;
import com.itheima.service.StudentService;
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.ArrayList;
import java.util.List;

/**

  • 业务层实现类
    */
    public class StudentServiceImpl implements StudentService {

    @Override
    public List<Student> findAll() {
    ArrayList<Student> list = null;
    SqlSession sqlSession = null;
    InputStream is = null;
    try{
    //1. 加载核心配置文件
    is = Resources.getResourceAsStream("MyBatisConfig.xml");

         <span class="hljs-comment">//2.获取SqlSession工厂对象</span>
         <span class="hljs-type">SqlSessionFactory</span> <span class="hljs-variable">sqlSessionFactory</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(is);
    
         <span class="hljs-comment">//3.通过工厂对象获取SqlSession对象</span>
         sqlSession = sqlSessionFactory.openSession(<span class="hljs-literal">true</span>);
    
         <span class="hljs-comment">//4.获取StudentDao接口的实现类对象</span>
         <span class="hljs-type">StudentDao</span> <span class="hljs-variable">mapper</span> <span class="hljs-operator">=</span> sqlSession.getMapper(StudentDao.class);
    
         <span class="hljs-comment">//5.调用实现类对象的方法,接收结果</span>
         list = mapper.findAll();
    
     } <span class="hljs-keyword">catch</span> (Exception e) {
         e.printStackTrace();
     } <span class="hljs-keyword">finally</span> {
         <span class="hljs-comment">//6.释放资源</span>
         <span class="hljs-keyword">if</span>(sqlSession != <span class="hljs-literal">null</span>) {
             sqlSession.close();
         }
         <span class="hljs-keyword">if</span>(is != <span class="hljs-literal">null</span>) {
             <span class="hljs-keyword">try</span> {
                 is.close();
             } <span class="hljs-keyword">catch</span> (IOException e) {
                 e.printStackTrace();
             }
         }
     }
    
     <span class="hljs-comment">//7.返回结果</span>
     <span class="hljs-keyword">return</span> list;
    

    }

    @Override
    public Student findById(Integer sid) {
    Student stu = null;
    SqlSession sqlSession = null;
    InputStream is = null;
    try{
    //1. 加载核心配置文件
    is = Resources.getResourceAsStream("MyBatisConfig.xml");

         <span class="hljs-comment">//2.获取SqlSession工厂对象</span>
         <span class="hljs-type">SqlSessionFactory</span> <span class="hljs-variable">sqlSessionFactory</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(is);
    
         <span class="hljs-comment">//3.通过工厂对象获取SqlSession对象</span>
         sqlSession = sqlSessionFactory.openSession(<span class="hljs-literal">true</span>);
    
         <span class="hljs-comment">//4.获取StudentDao接口的实现类对象</span>
         <span class="hljs-type">StudentDao</span> <span class="hljs-variable">mapper</span> <span class="hljs-operator">=</span> sqlSession.getMapper(StudentDao.class);
    
         <span class="hljs-comment">//5.调用实现类对象的方法,接收结果</span>
         stu = mapper.findById(sid);
    
     } <span class="hljs-keyword">catch</span> (Exception e) {
         e.printStackTrace();
     } <span class="hljs-keyword">finally</span> {
         <span class="hljs-comment">//6.释放资源</span>
         <span class="hljs-keyword">if</span>(sqlSession != <span class="hljs-literal">null</span>) {
             sqlSession.close();
         }
         <span class="hljs-keyword">if</span>(is != <span class="hljs-literal">null</span>) {
             <span class="hljs-keyword">try</span> {
                 is.close();
             } <span class="hljs-keyword">catch</span> (IOException e) {
                 e.printStackTrace();
             }
         }
     }
    
     <span class="hljs-comment">//7.返回结果</span>
     <span class="hljs-keyword">return</span> stu;
    

    }

    @Override
    public void save(Student student) {
    SqlSession sqlSession = null;
    InputStream is = null;
    try{
    //1. 加载核心配置文件
    is = Resources.getResourceAsStream("MyBatisConfig.xml");

         <span class="hljs-comment">//2.获取SqlSession工厂对象</span>
         <span class="hljs-type">SqlSessionFactory</span> <span class="hljs-variable">sqlSessionFactory</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(is);
    
         <span class="hljs-comment">//3.通过工厂对象获取SqlSession对象</span>
         sqlSession = sqlSessionFactory.openSession(<span class="hljs-literal">true</span>);
    
         <span class="hljs-comment">//4.获取StudentDao接口的实现类对象</span>
         <span class="hljs-type">StudentDao</span> <span class="hljs-variable">mapper</span> <span class="hljs-operator">=</span> sqlSession.getMapper(StudentDao.class);
    
         <span class="hljs-comment">//5.调用实现类对象的方法,接收结果</span>
         mapper.insert(student);
    
     } <span class="hljs-keyword">catch</span> (Exception e) {
         e.printStackTrace();
     } <span class="hljs-keyword">finally</span> {
         <span class="hljs-comment">//6.释放资源</span>
         <span class="hljs-keyword">if</span>(sqlSession != <span class="hljs-literal">null</span>) {
             sqlSession.close();
         }
         <span class="hljs-keyword">if</span>(is != <span class="hljs-literal">null</span>) {
             <span class="hljs-keyword">try</span> {
                 is.close();
             } <span class="hljs-keyword">catch</span> (IOException e) {
                 e.printStackTrace();
             }
         }
     }
    

    }

    @Override
    public void update(Student student) {
    SqlSession sqlSession = null;
    InputStream is = null;
    try{
    //1. 加载核心配置文件
    is = Resources.getResourceAsStream("MyBatisConfig.xml");

         <span class="hljs-comment">//2.获取SqlSession工厂对象</span>
         <span class="hljs-type">SqlSessionFactory</span> <span class="hljs-variable">sqlSessionFactory</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(is);
    
         <span class="hljs-comment">//3.通过工厂对象获取SqlSession对象</span>
         sqlSession = sqlSessionFactory.openSession(<span class="hljs-literal">true</span>);
    
         <span class="hljs-comment">//4.获取StudentDao接口的实现类对象</span>
         <span class="hljs-type">StudentDao</span> <span class="hljs-variable">mapper</span> <span class="hljs-operator">=</span> sqlSession.getMapper(StudentDao.class);
    
         <span class="hljs-comment">//5.调用实现类对象的方法,接收结果</span>
         mapper.update(student);
    
     } <span class="hljs-keyword">catch</span> (Exception e) {
         e.printStackTrace();
     } <span class="hljs-keyword">finally</span> {
         <span class="hljs-comment">//6.释放资源</span>
         <span class="hljs-keyword">if</span>(sqlSession != <span class="hljs-literal">null</span>) {
             sqlSession.close();
         }
         <span class="hljs-keyword">if</span>(is != <span class="hljs-literal">null</span>) {
             <span class="hljs-keyword">try</span> {
                 is.close();
             } <span class="hljs-keyword">catch</span> (IOException e) {
                 e.printStackTrace();
             }
         }
     }
    

    }

    @Override
    public void delete(Integer sid) {
    SqlSession sqlSession = null;
    InputStream is = null;
    try{
    //1. 加载核心配置文件
    is = Resources.getResourceAsStream("MyBatisConfig.xml");

         <span class="hljs-comment">//2.获取SqlSession工厂对象</span>
         <span class="hljs-type">SqlSessionFactory</span> <span class="hljs-variable">sqlSessionFactory</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SqlSessionFactoryBuilder</span>().build(is);
    
         <span class="hljs-comment">//3.通过工厂对象获取SqlSession对象</span>
         sqlSession = sqlSessionFactory.openSession(<span class="hljs-literal">true</span>);
    
         <span class="hljs-comment">//4.获取StudentDao接口的实现类对象</span>
         <span class="hljs-type">StudentDao</span> <span class="hljs-variable">mapper</span> <span class="hljs-operator">=</span> sqlSession.getMapper(StudentDao.class);
    
         <span class="hljs-comment">//5.调用实现类对象的方法,接收结果</span>
         mapper.delete(sid);
    
     } <span class="hljs-keyword">catch</span> (Exception e) {
         e.printStackTrace();
     } <span class="hljs-keyword">finally</span> {
         <span class="hljs-comment">//6.释放资源</span>
         <span class="hljs-keyword">if</span>(sqlSession != <span class="hljs-literal">null</span>) {
             sqlSession.close();
         }
         <span class="hljs-keyword">if</span>(is != <span class="hljs-literal">null</span>) {
             <span class="hljs-keyword">try</span> {
                 is.close();
             } <span class="hljs-keyword">catch</span> (IOException e) {
                 e.printStackTrace();
             }
         }
     }
    

    }
    }