2.持久层框架设计实现及MyBatis 源码解析 - 基于 XML 的 Mybatis 应用

一、Mybatis 相关概念

  1. 对象 / 关系数据库映射(ORM)
    • ORM全称Object/Relation Mapping:表示对象-关系映射的缩写
    • ORM完成⾯向对象的编程语⾔到关系数据库的映射。当ORM框架完成映射后,程序员既可以利⽤⾯向对象程序设计语⾔的简单易⽤性,⼜可以利⽤关系数据库的技术优势。ORM把关系数据库包装成⾯向对象的模型。ORM框架是⾯向对象设计语⾔与关系数据库发展不同步时的中间解决⽅案。采⽤ORM框架后,应⽤程序不再直接访问底层数据库,⽽是以⾯向对象的放松来操作持久化对象,⽽ORM框架则将这些⾯向对象的操作转换成底层SQL操作。ORM框架实现的效果:把对持久化对象的保存、修改、删除等操作,转换为对数据库的操作
  2. Mybatis 简介
    • MyBatis是⼀款优秀的基于ORM的半⾃动轻量级持久层框架,它⽀持定制化SQL、存储过程以及⾼级映射。MyBatis避免了⼏乎所有的JDBC代码和⼿动设置参数以及获取结果集。MyBatis可以使⽤简单的XML或注解来配置和映射原⽣类型、接⼝和Java的POJO (Plain Old Java Objects,普通⽼式Java对 象)为数据库中的记录。
  3. Mybatis 历史
    • 原是apache的⼀个开源项⽬iBatis, 2010年6⽉这个项⽬由apache software foundation 迁移到了google code,随着开发团队转投Google Code旗下,ibatis3.x正式更名为Mybatis ,代码于2013年11⽉迁移到Github。
    • iBATIS⼀词来源于“internet”和“abatis”的组合,是⼀个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO)
  4. Mybatis 优势
    • Mybatis是⼀个半⾃动化的持久层框架,对开发⼈员开说,核⼼sql还是需要⾃⼰进⾏优化,sql和java编码进⾏分离,功能边界清晰,⼀个专注业务,⼀个专注数据。
      在这里插入图片描述

二、Mybatis 基本应用

1.快速入门
  1. 官网地址:https://mybatis.org/mybatis-3/
  2. 开发步骤
    • 添加 MyBatis 的坐标(Maven依赖)
    • 创建 User 数据表
    • 编写 User实体类
    • 编写映射文件 UserMapper.xml
    • 编写核心配置文件 SqlmapConfig.xml
    • 编写测试类
  3. 环境搭建
    • 新建 Maven 工程,命名为 mybatis_quickStart,添加 Mybatis 的 Maven 依赖

      <properties>
          <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
          <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
          <java.version>1.8</java.version>
          <maven.compiler.source>1.8</maven.compiler.source>
          <maven.compiler.target>1.8</maven.compiler.target>
      </properties>
      <dependencies>
          <!--mybatis坐标-->
          <dependency>
              <groupId>org.mybatis</groupId>
              <artifactId>mybatis</artifactId>
              <version>3.4.5</version>
          </dependency>
          <!--mysql驱动坐标-->
          <dependency>
              <groupId>mysql</groupId>
              <artifactId>mysql-connector-java</artifactId>
              <version>5.1.6</version>
              <scope>runtime</scope>
          </dependency>
          <!--单元测试坐标-->
          <dependency>
              <groupId>junit</groupId>
              <artifactId>junit</artifactId>
              <version>4.12</version>
              <scope>test</scope>
          </dependency>
          <!--⽇志坐标-->
          <dependency>
              <groupId>log4j</groupId>
              <artifactId>log4j</artifactId>
              <version>1.2.12</version>
          </dependency>
      </dependencies>
      
    • 创建 User 数据表
      在这里插入图片描述

    • 编写 User实体类

      public class User {
          private Integer id;
          private String username;
          // set、get、toString 方法省略。。。
      }
      
    • 编写映射文件 UserMapper.xml

      <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE mapper
              PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
              "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      <mapper namespace="user">
          <select id="selectList" resultType="com.mfc.entity.User">
              select * from user
          </select>
      </mapper>
      
    • 编写核心配置文件 SqlMapConfig.xml

      <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-config.dtd">
      <configuration>
          <!-- default 指定默认环境的名称 -->
          <environments default="dev">
              <!-- id指定当前环境名称 -->
              <environment id="dev">
                  <!-- 事务管理类型,交由 JDBC 管理事务 -->
                  <transactionManager type="JDBC"></transactionManager>
                  <!-- 指定当前数据源类型是连接池 -->
                  <dataSource type="POOLED">
                      <!-- 数据源配置的基本参数 -->
                      <property name="driver" value="com.mysql.jdbc.Driver"/>
                      <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                      <property name="username" value="root"/>
                      <property name="password" value="root"/>
                  </dataSource>
              </environment>
          </environments>
          <mappers>
              <mapper resource="mapper/UserMapper.xml"></mapper>
          </mappers>
      </configuration>
      
    • 编写测试类

      @org.junit.Test
      public void test() throws Exception{
          InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
          SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
          SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
          SqlSession sqlSession = sqlSessionFactory.openSession();
          List<User> users = sqlSession.selectList("user.selectList");
          for (User user : users) {
              System.out.println(user);
          }
          sqlSession.close();
      }
      
2.增删改查
  1. MyBatis 的插入操作
    • 编写 UserMapper.xml 映射文件
      <mapper namespace="user">
          <insert id="insertUser" parameterType="com.mfc.entity.User">
              insert into user values(#{id},#{username})
          </insert>
      </mapper>
      
    • 编写插入实体 User 的代码
      @org.junit.Test
      public void testInsert() throws Exception{
          InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
          SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
          SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
          SqlSession sqlSession = sqlSessionFactory.openSession();
          User user = new User();
          user.setId(4);
          user.setUsername("FanchengMeng");
          sqlSession.insert("user.insertUser",user);
          sqlSession.commit();
          sqlSession.close();
      }
      
    • 插入操作注意的问题
      • 插入语句使用 insert 语句
      • 在映射文件中使用 parameterType 属性指定要插入的数据类型
      • SQL 语句中使用 #{实体属性名} 方式引用实体中的属性值
      • 插入操作使用的 API 是 sqlSession.insert(“命名空间.id”, 实体对象);
      • 插入操作设计数据库数据变化,所以要使用 sqlSession 对象显示的提交事务,即 sqlSession.commit()。(也可以在创建 SqlSession 时设置自动提交事务)
      SqlSession sqlSession = sqlSessionFactory.openSession(true);
      
  2. Mybatis 的删除操作
    • 编写 UserMapper.xml 映射文件
      <mapper namespace="user">
          <delete id="deleteUser" parameterType="java.lang.Integer">
              delete from user where id=#{id}
          </delete>
      </mapper>
      
    • 编写删除实体 User 的代码
      @org.junit.Test
      public void testDelete() throws Exception{
          InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
          SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
          SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
          SqlSession sqlSession = sqlSessionFactory.openSession();
          sqlSession.delete("user.deleteUser",1);
          sqlSession.commit();
          sqlSession.close();
      }
      
    • 删除操作注意的问题
      • 删除语句使用 delete 标签
      • Sql 语句中使用 #{任意字符串} 方式引用传递的单个参数
      • 删除操作使用的 API 是 sqlSession.delete(“命名空间.id”, Object);
  3. MyBatis 的修改操作
    • 编写 UserMapper.xml 映射文件
      <mapper namespace="user">
          <update id="updateUser" parameterType="com.mfc.entity.User">
              update user set username=#{username} where id=#{id}
          </update>
      </mapper>
      
    • 编写修改实体 User 的代码
      @org.junit.Test
      public void testUpdate() throws Exception{
          InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
          SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
          SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
          SqlSession sqlSession = sqlSessionFactory.openSession();
          User user = new User();
          user.setId(3);
          user.setUsername("zhangsan");
          sqlSession.update("user.updateUser",user);
          sqlSession.commit();
          sqlSession.close();
      }
      
    • 修改操作注意的问题
      • 修改语句使用 update 标签
      • 修改操作使用的 API 是 sqlSession.update(“命名空间.id”, 实体对象)
3.Mybatis 映射文件解释
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- default 指定默认环境的名称 -->
    <environments default="dev">
        <!-- id指定当前环境名称 -->
        <environment id="dev">
            <!-- 事务管理类型,交由 JDBC 管理事务 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 指定当前数据源类型是连接池 -->
            <dataSource type="POOLED">
                <!-- 数据源配置的基本参数 -->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mapper/UserMapper.xml"></mapper>
    </mappers>
</configuration>
4.核心配置文件分析
  1. MyBatis 核心配置文件层级关系
    在这里插入图片描述

  2. environments 标签

    • 数据库环境的配置,支持多环境配置
      *
    • 其中,事务管理器(transactionManager)类型有两种
      • JDBC:这个配置就是直接使用了 JDBC 的提交和回滚设置,它依赖于从数据源得到的链接来管理事务作用域
      • MANAGED:此配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。默认情况下它会关闭连接,然而一些容器并不希望这样,因此需要将 closeConnection 属性设置为 false 来阻止它默认的关闭行为
    • 其中,数据源(DataSource)类型有三种:
      • UNPOOLED:这个数据源的实现只是每次被请求时打开和关闭连接
      • POOLED:这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来
      • JNDI:这个数据源的实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用
  3. mapper 标签

    • 该标签的作用是加载映射,加载方式有下面几种
      • 使用相对于类路径的资源引用:
        <mapper resource="mapper/UserMapper.xml"></mapper>
        
      • 使用完全限定资源定位符(URL):
        <mapper url="file:///var/mappers/UserMapper.xml"/>
        
      • 使用映射器接口实现类的完全限定类名:
        <mapper class="com.mfc.dao.UserDao"/>
        
      • 将包内的映射器接口实现全部注册为映射器
        <package name="com.mfc.dao"/>
        
5.Mybatis 常用 API 介绍
  1. SqlSession 工厂构造器 SqlSessionFactoryBuilder
    • 常用 API:sqlSessionFactoryBuilder.build(inputStream);
    • 通过加载 MyBatis 的核心文件的输入流的形式构建一个 SqlSessionFactory 对象
      InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
      SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
      SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
      
    • 其中,Resources 工具类在 org.apache.ibatis.io 包中,Resources 类帮助我们从类路径下、文件系统或一个 web URL 中加载资源文件
  2. SqlSession 工厂对象 SqlSessionFactory
    • SqlSessionFactory 有多个方法创建 SqlSession 实例,常用的有两个:
      • openSession():会默认开启一个事务,但事务不会自动提交,也就意味着需要手动提交事务,更新操作数据才会持久化到数据库中
      • openSession(boolean autoCommit):参数为是否自动提交事务,如果设置为 true,那么不需要手动提交事务
  3. SqlSession 会话对象
    • SqlSession 实例在 Mybatis 中是非常强大的一个类。在这里可以看到所有执行语句、提交或回滚事务和获取映射器实例的方法。
    • 执行语句的方法主要有:
      <T> T selectOne(String statement, Object parameter)
      <E> List<E> selectList(String statement, Object parameter)
      int insert(String statement, Object parameter)
      int update(String statement, Object parameter)
      int delete(String statement, Object parameter)
      
    • 操作事务的方法主要有:
      void commit()
      void rollback()
      
6.MyBatis 的 Dao 层实现(传统模式)
  1. 编写 UserDao 接口
    public interface UserDao {
        public List<User> findAll() throws Exception;
    }
    
  2. 编写 UserDaoImpl 实现
    public class UserDaoImpl implements UserDao {
        @Override
        public List<User> findAll() throws Exception {
            InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
            SqlSession sqlSession = sqlSessionFactory.openSession();
            List<User> users = sqlSession.selectList("user.selectList");
            sqlSession.close();
            return users;
        }
    }
    
  3. 测试传统方式
    @org.junit.Test
    public void testSelect() throws Exception{
        UserDao userDao = new UserDaoImpl();
        List<User> users = userDao.findAll();
        for (User user : users) {
            System.out.println(user);
        }
    }
    
7.MyBatis 的 Dao 层实现(代理模式)
  1. 采用 MyBatis 的代理开发方式实现 Dao 层的开发,这种方式是现在企业中使用的主流方式

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

  3. Mapper 接口开发遵循以下规范

    • Mapper.xml 文件中的 namespace 与 mapper 接口的全限定名相同
    • Mapper 接口方法名和 Mapper.xml 中定义的每个 statement 的 id 相同
    • Mapper 接口方法的输入参数类型和 mapper.xml 中定义的每个 Sql 的 parameterType 的类型相同
    • Mapper 接口方法的输出参数类型和 mapper.xml 中定义的每个 Sql 的 resultType 的类型相同
      在这里插入图片描述
  4. 测试

    • UserMapper.xml 映射文件编写
      <mapper namespace="com.mfc.dao.UserDao">
          <select id="findAll" resultType="com.mfc.entity.User">
              select * from user
          </select>
      </mapper>
      
    • UserDao 接口编写
      public interface UserDao {
          public List<User> findAll() throws Exception;
      }
      
    • 测试类:
      @org.junit.Test
      public void testSelect() throws Exception{
          InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
          SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
          SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
          SqlSession sqlSession = sqlSessionFactory.openSession();
          UserDao userDao = sqlSession.getMapper(UserDao.class);
          List<User> all = userDao.findAll();
          for (User user : all) {
              System.out.println(user);
          }
          sqlSession.close();
      }
      

三、MyBatis 配置文件深入

1.核心配置文件 SqlMapConfig.xml
  1. MyBatis 核心配置文件层级关系
    在这里插入图片描述

  2. environments 标签

    • 数据库环境的配置,支持多环境配置
      *
    • 其中,事务管理器(transactionManager)类型有两种
      • JDBC:这个配置就是直接使用了 JDBC 的提交和回滚设置,它依赖于从数据源得到的链接来管理事务作用域
      • MANAGED:此配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。默认情况下它会关闭连接,然而一些容器并不希望这样,因此需要将 closeConnection 属性设置为 false 来阻止它默认的关闭行为
    • 其中,数据源(DataSource)类型有三种:
      • UNPOOLED:这个数据源的实现只是每次被请求时打开和关闭连接
      • POOLED:这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来
      • JNDI:这个数据源的实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用
  3. mapper 标签

    • 该标签的作用是加载映射,加载方式有下面几种
      • 使用相对于类路径的资源引用:
        <mapper resource="mapper/UserMapper.xml"></mapper>
        
      • 使用完全限定资源定位符(URL):
        <mapper url="file:///var/mappers/UserMapper.xml"/>
        
      • 使用映射器接口实现类的完全限定类名:
        <mapper class="com.mfc.dao.UserDao"/>
        
      • 将包内的映射器接口实现全部注册为映射器
        <package name="com.mfc.dao"/>
        
  4. properties 标签

    • 实际开发中,习惯将数据源的配置信息单独抽取成一个 properties 文件,该标签可以加载额外配置的 properties 文件
      在这里插入图片描述
  5. typeAliases 标签

    • 类型别名是为 Java 类型设置一个短的名字。原来的类型名称如下
      在这里插入图片描述

    • 配置 typeAliases ,为 com.mfc.entity.User 定义别名为 user

      • 方法一:使用 typeAlias 标签取别名
        在这里插入图片描述

      • 方法二:使用 package 标签取别名。给实体类所在的包下面的所有实体类取别名,别名就是类名,并且不区分大小写
        在这里插入图片描述

    • 上面是程序员可以自定义的别名,Mybatis 框架已经为我们设置好了一些常用的别名
      在这里插入图片描述

2.映射配置文件 mapper.xml
  1. 动态 SQL:MyBatis 的映射文件中,前面我们使用的 SQL 都比较简单,有些时候业务逻辑复杂时,SQL 会是动态变化的,此时前面那些简单的 SQL 就不能满足要求了

    • 动态 SQL 之 标签:根据实体类的不同取值,使用不同的 SQL 语句来进行查询。比如 id 不为空的时候,可以根据 id 查询,username 不为空的时候,可以根据 username 查询。这种情况通常在多条件组合查询中遇到

      • Mapper.xml 编写
        <mapper namespace="com.mfc.dao.UserDao">
            <select id="selectList" resultType="com.mfc.entity.User" parameterType="com.mfc.entity.User">
                select * from user
                <where>
                    <if test="id != 0">
                        and id = #{id}
                    </if>
                    <if test="username != null">
                        and username = #{username}
                    </if>
                </where>
            </select>
        </mapper>
        
      • 测试类编写:
        @org.junit.Test
        public void test() throws Exception{
            InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
            SqlSession sqlSession = sqlSessionFactory.openSession();
            User user = new User();
            user.setId(2);
            user.setUsername("zahngsan");
            List<User> users = sqlSession.selectList("com.mfc.dao.UserDao.selectList",user);
            for (User user1 : users) {
                System.out.println(user1);
            }
            sqlSession.close();
        }
        
      • 控制台打印SQL:
        • 先在SqlMapConfig.xml 中开启日志打印
          在这里插入图片描述

        • 运行测试类,查看控制台SQL
          在这里插入图片描述

    • 动态 SQL 之 标签:循环执行 SQL 的拼接操作,如:select * from user where id in (1,2,3)

      • 标签的属性含义:
        • collection:代表要遍历的几何元素,注意编写时不要写 #{}
        • open:代表语句的开始部分
        • close:代表语句的结束部分
        • item:代表遍历集合的每个元素,生成的变量名
        • sperator:代表分隔符
      • Mapper.xml 编写
        <mapper namespace="com.mfc.dao.UserDao">
            <select id="findByIds" parameterType="list" resultType="com.mfc.entity.User">
                select * from user
                <where>
                    <foreach collection="array" open="id in(" close=")" item="id" separator=",">
                        #{id}
                    </foreach>
                </where>
            </select>
        </mapper>
        
      • 测试类编写:
        @org.junit.Test
        public void testFindByIds() throws Exception{
            InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
            SqlSession sqlSession = sqlSessionFactory.openSession();
            int[] arr = {1,2,3,4};
            List<User> users = sqlSession.selectList("com.mfc.dao.UserDao.findByIds", arr);
            for (User user : users) {
                System.out.println(user);
            }
        }
        
      • 控制台打印结果
        在这里插入图片描述
  2. SQL 片段抽取

    • Sql 中可以将重复的 Sql 提取出来,使用时用 include 引用即可,最终达到 SQL 重用的目的
      在这里插入图片描述

四、MyBatis 复杂映射开发

1.一对一查询
  1. 一对一查询模型

    1. 用户表和订单表的关系为:一个用户有多个订单,一个订单只从属于一个用户
    2. 一对一查询的需求:查询一个订单,与此同时查询出该订单的所属用户
      在这里插入图片描述
  2. 一对一查询语句

    1. 查看 orders 表数据
      在这里插入图片描述

    2. 查看 user 表数据
      在这里插入图片描述

    3. 编写一对一查询语句并执行:select * from orders o,user u where o.uid=u.id;
      在这里插入图片描述

  3. MyBatis 实现一对一

    1. 编写 Orders 实体类

      public class Orders {
          private Integer id;
          private String ordertime;
          private Double total;
          private User user;
          // set、get、toString 方法省略。。。
      }
      
    2. 编写 User 实体类

      public class User {
         private Integer id;
         private String username;
         // set、get、toString 方法省略。。。
      }
      
    3. 创建 OrdersDao 接口

      public interface OrdersDao {
          public List<Orders> selectOrders();
      }
      
    4. 编写 OrderMapper.xml 映射文件

      <mapper namespace="com.mfc.dao.OrdersDao">
          <resultMap id="orderMap" type="com.mfc.entity.Orders">
              <result property="id" column="id"></result>
              <result property="ordertime" column="ordertime"></result>
              <result property="total" column="total"></result>
              <association property="user" javaType="com.mfc.entity.User">
                  <id property="id" column="uid"></id>
                  <result property="username" column="username"></result>
              </association>
          </resultMap>
          <select id="selectOrders" resultMap="orderMap">
              select * from orders o,user u where o.uid=u.id
          </select>
      </mapper>
      
    5. 编写测试类

      @org.junit.Test
      public void test() throws Exception{
          InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
          SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
          SqlSessionFactory factory = builder.build(inputStream);
          SqlSession sqlSession = factory.openSession();
          OrdersDao ordersDao = sqlSession.getMapper(OrdersDao.class);
          List<Orders> orders = ordersDao.selectOrders();
          for (Orders order : orders) {
              System.out.println(order);
          }
      }
      
    6. 测试结果
      在这里插入图片描述

2.一对多查询
  1. 一对多查询模型

    1. 用户表和订单表的关系为:一个用户有多个订单,一个订单只从属一个用户
    2. 一对多查询需求:查询一个用户,以此同时查询出该用户具有的订单
      在这里插入图片描述
  2. 一对多查询语句

    1. 查看 orders 表数据
      在这里插入图片描述

    2. 查看 user 表数据
      在这里插入图片描述

    3. 编写一对多查询语句并执行:select *,o.id oid from user u left join orders o on o.uid=u.id
      在这里插入图片描述

  3. MyBatis 实现一对多

    1. 编写 Orders 实体类
      public class Orders {
          private Integer id;
          private String ordertime;
          private Double total;
          private Integer uid;
          // set、get、toString 方法省略。。。
      }
      
    2. 编写 User 实体类
      public class User {
          private Integer id;
          private String username;
          private List<Orders> orders = new ArrayList<>();
          // set、get、toString方法省略。。。
      }
      
    3. 编写 UserDao 接口
      public interface UserDao {
          public List<User> selectUser() throws Exception;
      }
      
    4. 编写 UserMapper.xml 映射文件
      <mapper namespace="com.mfc.dao.UserDao">
          <resultMap id="userMap" type="com.mfc.entity.User">
              <result property="id" column="id"></result>
              <result property="username" column="username"></result>
              <collection property="orders" ofType="com.mfc.entity.Orders">
                  <id property="id" column="oid"></id>
                  <result property="ordertime" column="ordertime"></result>
                  <result property="total" column="total"></result>
              </collection>
          </resultMap>
      
          <select id="selectUser" resultMap="userMap">
              select *,o.id oid from user u left join orders o on o.uid=u.id
          </select>
      </mapper>
      
    5. 测试类
      @org.junit.Test
      public void test() throws Exception{
          InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
          SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
          SqlSessionFactory factory = builder.build(inputStream);
          SqlSession sqlSession = factory.openSession();
          UserDao userDao = sqlSession.getMapper(UserDao.class);
          List<User> users = userDao.selectUser();
          for (User user : users) {
              System.out.println(user);
          }
      }
      
    6. 测试结果
      在这里插入图片描述
3.多对多查询
  1. 多对多查询模型

    • ⽤户表和⻆⾊表的关系为,⼀个⽤户有多个⻆⾊,⼀个⻆⾊被多个⽤户使⽤
    • 多对多查询的需求:查询⽤户同时查询出该⽤户的所有⻆⾊
      在这里插入图片描述
  2. 多对多查询语句

    • 查看 user 表数据
      在这里插入图片描述

    • 查看中间表 user_role 数据
      在这里插入图片描述

    • 查看 role 表数据
      在这里插入图片描述

    • 编写多对多查询语句并执行

      • 查询语句
      SELECT
         u.*, r.id rid,
         r.rolename rolename
      FROM
         USER u
      LEFT JOIN user_role ur ON u.id = ur.uid
      INNER JOIN role r ON ur.rid = r.id
      
      • 执行效果
        在这里插入图片描述
  3. MyBatis 实现多对多

    • 编写 User 实体类
      public class User {
          private Integer id;
          private String username;
          private List<Role> roles = new ArrayList<>();
          // set、get、toString方法省略。。。
      }
      
    • 编写 Role 实体类
      public class Role {
          private Integer id;
          private String rolename;
          // set、get、toString方法省略。。。
      }
      
    • 编写 UserDao 接口
      public interface UserDao {
          public List<User> selectUser() throws Exception;
      }
      
    • 编写 UserMapper.xml 映射文件
      <mapper namespace="com.mfc.dao.UserDao">
          <resultMap id="userMap" type="com.mfc.entity.User">
              <result property="id" column="id"></result>
              <result property="username" column="username"></result>
              <collection property="roles" ofType="com.mfc.entity.Role">
                  <id property="id" column="rid"></id>
                  <result property="rolename" column="rolename"></result>
              </collection>
          </resultMap>
      
          <select id="selectUser" resultMap="userMap">
              SELECT
                  u.*, r.id rid,
                  r.rolename rolename
              FROM
                  USER u
              LEFT JOIN user_role ur ON u.id = ur.uid
              INNER JOIN role r ON ur.rid = r.id
          </select>
      </mapper>
      
    • 测试类
          @org.junit.Test
          public void test() throws Exception{
              InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
              SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
              SqlSessionFactory factory = builder.build(inputStream);
              SqlSession sqlSession = factory.openSession();
              UserDao userDao = sqlSession.getMapper(UserDao.class);
              List<User> users = userDao.selectUser();
      
              for (User user : users) {
                  System.out.println(user.getUsername());
                  List<Role> roles = user.getRoles();
                  for (Role role : roles) {
                      System.out.println(role);
                  }
                  System.out.println("==================");
              }
          }
      
    • 测试结果
      在这里插入图片描述

在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值