Mybatis进阶:接口代理方式实现dao层,动态sql语句,分页插件,Mybatis多表操做

知识点梳理

详细讲义

一.接口代理方式实现Dao ***

1.1 代理开发方式介绍

  • 采用 Mybatis 的代理开发方式实现 DAO 层的开发,这种方式是咱们后面进入企业的主流。java

  • Mapper 接口开发方法只须要程序员编写Mapper 接口(至关于Dao 接口),由Mybatis 框架根据接口定义建立接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法mysql

  • 总结:接口代理方式,其实就咱们本身不用实现MapperImpl(持久层实现类),mybatis经过接口代理的方式帮助咱们实现git

  • Mapper 接口开发须要遵循如下规范:程序员

    1) Mapper.xml文件中的namespace与mapper接口的全限定名相同github

    2) Mapper接口方法名和Mapper.xml中定义的每一个statement的id相同sql

    3) Mapper接口方法的输入参数类型和mapper.xml中定义的每一个sql的parameterType的类型相同数据库

    4) Mapper接口方法的输出参数类型和mapper.xml中定义的每一个sql的resultType的类型相同apache

  • 以下图:session

 

 

1.2 代码实现

  • 实现步骤:mybatis

  1. 删除 mapper 层接口的实现类(新建一个项目mybatis02,将第一天的代码所有复制过来)

  2. 修改映射配置文件

    <!-- 将命名空间修改成StudentMapper全路径名-->
    <mapper namespace="com.itheima.mapper.StudentMapper">
  3. 修改 service 层接口的实现类,采用接口代理方式实现功能(由于如今没有持久层实现类了,因此业务层没法直接调用,须要本身实现而且调用代理接口方式的MapperImpl)

    package com.itheima.service.impl;

    import com.itheima.bean.Student;
    import com.itheima.mapper.StudentMapper;
    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.List;
    /*
       业务层实现类
    */
    public class StudentServiceImpl implements StudentService {

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

               //2.获取SqlSession工厂对象
               SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

               //3.经过工厂对象获取SqlSession对象
               sqlSession = sqlSessionFactory.openSession(true);

               //4.获取StudentMapper接口的实现类对象
               StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // StudentMapper mapper = new StudentMapperImpl();

               //5.经过实现类对象调用方法,接收结果
               list = mapper.selectAll();

          } catch (Exception e) {

          } finally {
               //6.释放资源
               if(sqlSession != null) {
                   sqlSession.close();
              }
               if(is != null) {
                   try {
                       is.close();
                  } catch (IOException e) {
                       e.printStackTrace();
                  }
              }
          }

           //7.返回结果
           return list;
      }

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

               //2.获取SqlSession工厂对象
               SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

               //3.经过工厂对象获取SqlSession对象
               sqlSession = sqlSessionFactory.openSession(true);

               //4.获取StudentMapper接口的实现类对象
               StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // StudentMapper mapper = new StudentMapperImpl();

               //5.经过实现类对象调用方法,接收结果
               stu = mapper.selectById(id);

          } catch (Exception e) {

          } finally {
               //6.释放资源
               if(sqlSession != null) {
                   sqlSession.close();
              }
               if(is != null) {
                   try {
                       is.close();
                  } catch (IOException e) {
                       e.printStackTrace();
                  }
              }
          }

           //7.返回结果
           return stu;
      }

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

               //2.获取SqlSession工厂对象
               SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

               //3.经过工厂对象获取SqlSession对象
               sqlSession = sqlSessionFactory.openSession(true);

               //4.获取StudentMapper接口的实现类对象
               StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // StudentMapper mapper = new StudentMapperImpl();

               //5.经过实现类对象调用方法,接收结果
               result = mapper.insert(stu);

          } catch (Exception e) {

          } finally {
               //6.释放资源
               if(sqlSession != null) {
                   sqlSession.close();
              }
               if(is != null) {
                   try {
                       is.close();
                  } catch (IOException e) {
                       e.printStackTrace();
                  }
              }
          }

           //7.返回结果
           return result;
      }

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

               //2.获取SqlSession工厂对象
               SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

               //3.经过工厂对象获取SqlSession对象
               sqlSession = sqlSessionFactory.openSession(true);

               //4.获取StudentMapper接口的实现类对象
               StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // StudentMapper mapper = new StudentMapperImpl();

               //5.经过实现类对象调用方法,接收结果
               result = mapper.update(stu);

          } catch (Exception e) {

          } finally {
               //6.释放资源
               if(sqlSession != null) {
                   sqlSession.close();
              }
               if(is != null) {
                   try {
                       is.close();
                  } catch (IOException e) {
                       e.printStackTrace();
                  }
              }
          }

           //7.返回结果
           return result;
      }

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

               //2.获取SqlSession工厂对象
               SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

               //3.经过工厂对象获取SqlSession对象
               sqlSession = sqlSessionFactory.openSession(true);

               //4.获取StudentMapper接口的实现类对象
               StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // StudentMapper mapper = new StudentMapperImpl();

               //5.经过实现类对象调用方法,接收结果
               result = mapper.delete(id);

          } catch (Exception e) {

          } finally {
               //6.释放资源
               if(sqlSession != null) {
                   sqlSession.close();
              }
               if(is != null) {
                   try {
                       is.close();
                  } catch (IOException e) {
                       e.printStackTrace();
                  }
              }
          }

           //7.返回结果
           return result;
      }
    }
  • 最后测试:经过StudentController的测试类来直接测试,可以测试经过便可

1.3 源码分析

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

    • 经过动态代理开发模式,咱们只编写一个接口,不写实现类,咱们经过 getMapper() 方法最终获取到 org.apache.ibatis.binding.MapperProxy 代理对象,而后执行功能,

    • 而这个代理对象正是 MyBatis 使用了 JDK 的动态代理技术,帮助咱们生成了代理实现类对象。从而能够进行相关持久化操做。

    • 跟踪getMapper方法,最终能够跟踪到以下代码:这个代码就是咱们以前本身实现动态代理的代码:

       

       

  • 分析方法是如何执行的?

    • 分析过程:

      • 跟踪mapper.insert方法,代码打断点,而后调试跟踪

      • 代码执行到insert以后,进入方法的执行,而后就进入到了invoke方法(动态代理执行方法,都会执行invoke)

      • 在invoke中调用了mapperMethod.execute()方法

      • 这个方法中经过 switch 语句根据操做类型来判断是新增、修改、删除、查询操做,

      • 最后一步回到了 MyBatis 最原生的 SqlSession 方式来执行增删改查

         

         

1.4 @Param

  1. 给映射文件的sql传递多个参数,除了封装对象,还能够经过注解Param来实现

  2. 代码:StudentMapper增长

    //根据姓名或年龄查询
       public abstract List<Student> selectByNameOrAge(@Param("p1") String name , @Param("p2") Integer age);
  3. 配置:

    <select id="selectByNameOrAge" resultType="student" >
       <include refid="select"/> WHERE name = #{p1} OR age = #{p2}
    </select>
  4. 经过@Param配置的参数名,在映射中就能够经过#{}来获取

1.5 知识小结

  • 接口代理方式可让咱们只编写接口便可,而实现类对象由 MyBatis 生成

  • 实现规则 :

    1. 映射配置文件中的名称空间必须和 Dao 层接口的全类名相同

    2. 映射配置文件中的增删改查标签的 id 属性必须和 Dao 层接口的方法名相同

    3. 映射配置文件中的增删改查标签的 parameterType 属性必须和 Dao 层接口方法的参数相同

    4. 映射配置文件中的增删改查标签的 resultType 属性必须和 Dao 层接口方法的返回值相同

  • 获取动态代理对象

    • 获取动态代理对象 SqlSession 功能类中的 getMapper() 方法

二. 动态sql语句

2.1 动态sql语句概述

  • Mybatis 的映射文件中,前面咱们的 SQL 都是比较简单的,

  • 有些时候业务逻辑复杂时,咱们的 SQL是动态变化的,此时在前面的学习中咱们的 SQL 就不能知足要求了。

  • 例如,有时候查询条件是三个,有时候是两个:

     

     

  • 代码:

    1. StudentMapper.xml增长多条件sql

       

       

    2. Mapper接口:增长多条件查询方法

      //多条件查询
      public abstract List<Student> selectCondition(Student stu);
    3. 测试类:com.itheima.dynamic.Test01

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

             //2.获取SqlSession工厂对象
             SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

             //3.经过工厂对象获取SqlSession对象
             SqlSession sqlSession = sqlSessionFactory.openSession(true);

             //4.获取StudentMapper接口的实现类对象
             StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

             Student stu = new Student();
             stu.setId(2);
             stu.setName("李四");
             stu.setAge(24);

             //5.调用实现类的方法,接收结果
             List<Student> list = mapper.selectCondition(stu);

             //6.处理结果
             for (Student student : list) {
                 System.out.println(student);
            }

             //7.释放资源
             sqlSession.close();
             is.close();
        }
    4. 3个条件结果

       

       

    5. 2个条件(将setAge屏蔽掉)结果:若是有一个参数没有传递,默认是null,这确定查询不到数据

       

       

      • 那如何解决这种问题呢?咱们可能会根据不一样需求要利用同一个功能,可是查询条件可能会变化

      • 在映射文件中如何动态配置sql呢?

      • 利用动态sql标签

  • 动态sql标签

     

     

2.2 动态 SQL 之<if> ***

  • 咱们根据实体类的不一样取值,使用不一样的 SQL语句来进行查询。

  • 好比在 id若是不为空时能够根据id查询,若是username 不一样空时还要加入用户名做为条件。

  • 这种状况在咱们的多条件组合查询中常常会碰到。

  • 咱们须要动态sql标签where和if。

  • <where>:条件标签,若是有动态条件,则使用该标签代替where关键字

  • <if>:条件判断标签

     <if test="条件判断">
    拼接的查询条件
    </if>
  • 以下图:

<select id="selectCondition" resultType="student" parameterType="student">
  select * from student
   <where>
       <if test="id != null">
          id = #{id}
       </if>
       <if test="name != null">
          AND name = #{name} <!--若是没有传递id,会不会直接是where and name=xxx,不会,mybatis会作特殊处理-->
       </if>
       <if test="age != null">
          AND age = #{age}
       </if>
   </where>
</select>
  • 总结语法:

<where>:条件标签。若是有动态条件,则使用该标签代替 where 关键字。
<if>:条件判断标签。语法以下:
<if test=“条件判断”>
拼接的查询条件
</if>

2.3 动态 SQL 之<foreach> ***

 

 

  • 接下来咱们来写代码:

  • 增长映射配置:

<select id="selectByIds" resultType="student" parameterType="list">
   <include refid="select"/>
   <where>
       <foreach collection="list" open="id IN (" close=")" item="id" separator=",">
          #{id}
       </foreach>
   </where>
</select>
  • 增长接口:

//根据多个id查询
public abstract List<Student> selectByIds(List<Integer> ids);
  • Test01中增长测试方法:

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

   //2.获取SqlSession工厂对象
   SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

   //3.经过工厂对象获取SqlSession对象
   SqlSession sqlSession = sqlSessionFactory.openSession(true);

   //4.获取StudentMapper接口的实现类对象
   StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

   List<Integer> ids = new ArrayList<>();
   ids.add(1);
   ids.add(2);
   ids.add(3);

   //5.调用实现类的方法,接收结果
   List<Student> list = mapper.selectByIds(ids);

   //6.处理结果
   for (Student student : list) {
       System.out.println(student);
  }

   //7.释放资源
   sqlSession.close();
   is.close();
}
  • 测试:给ids集合中增长1和2测试,而后再集合中增长3来测试,发现均可以

2.4 SQL片断抽取

  • 咱们发如今映射文件中的sql语句,有不少都有重复的部分,那怎么处理呢?

  • 经过sql片断抽取:

 

 

  • Sql 中可将重复的 sql 提取出来,使用时用 include 引用便可,最终达到 sql 重用的目的

  • 代码:

  • 映射文件:

<mapper namespace="com.itheima.mapper.StudentMapper">
<!--抽取-->
   <sql id="select" >SELECT * FROM student</sql>
   <select id="selectAll" resultType="student">
       <!--引用-->
       <include refid="select"/>
   </select>

   <select id="selectById" resultType="student" parameterType="int">
       <!--引用-->
       <include refid="select"/> WHERE id = #{id}
   </select>

   <insert id="insert" parameterType="student">
      INSERT INTO student VALUES (#{id},#{name},#{age})
   </insert>

   <update id="update" parameterType="student">
      UPDATE student SET name = #{name},age = #{age} WHERE id = #{id}
   </update>

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

   <select id="selectCondition" resultType="student" parameterType="student">
       <!--引用-->
       <include refid="select"/>
       <where>
           <if test="id != null">
              id = #{id}
           </if>
           <if test="name != null">
              AND name = #{name}
           </if>
           <if test="age != null">
              AND age = #{age}
           </if>
       </where>
   </select>

   <select id="selectByIds" resultType="student" parameterType="list">
       <!--引用-->
       <include refid="select"/>
       <where>
           <foreach collection="list" open="id IN (" close=")" item="id" separator=",">
              #{id}
           </foreach>
       </where>
   </select>
</mapper>

2.5 知识小结

 

 

 

三. 分页插件 ***

3.1 分页插件介绍

  • 常见的分页效果:例如百度:

 

 

  • 分页能够将不少条结果进行分页显示

  • 若是当前在第一页,则没有上一页。若是当前在最后一页,则没有下一页

  • 须要明确当前是第几页,这一页中显示多少条结果

  • MyBatis分页插件总结

    • 在企业级开发中,分页也是一种常见的技术

    • 而目前使用的 MyBatis 是不带分页功能的,若是想实现分页的 功能,须要咱们手动编写 LIMIT 语句

    • 可是不一样的数据库实现分页的 SQL 语句也是不一样的,因此手写分页 成本较高

    • 这个时候就能够借助分页插件来帮助咱们实现分页功能

    • PageHelper:第三方分页助手。将复杂的分页操做进行封装,从而让分页功能变得很是简单

3.2 分页插件的使用

  • MyBatis可使用第三方的插件来对功能进行扩展,分页助手PageHelper是将分页的复杂操做进行封装,使用简单的方式便可得到分页的相关数据

  • 开发步骤:

  • ①导入与PageHelper的jar包 “02-MyBatis进阶\资料\分页插件jar包”

  • ②在mybatis核心配置文件中配置PageHelper插件

<!-- 注意:分页助手的插件,配置在typeAliases以后。interceptor:拦截器,插件都是以拦截器形式实现的 -->
<plugins>
       <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
  • ③测试:新建com.itheima.paging.Test01

package com.itheima.paging;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.itheima.bean.Student;
import com.itheima.mapper.StudentMapper;
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.Test;

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

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

       //2.获取SqlSession工厂对象
       SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

       //3.经过工厂对象获取SqlSession对象
       SqlSession sqlSession = sqlSessionFactory.openSession(true);

       //4.获取StudentMapper接口的实现类对象
       StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

       //经过分页助手来实现分页功能 startPage参数1:当前页码,参数2:每页显示几条
       // 第一页:显示3条数据 pageNum,pageSize
       //PageHelper.startPage(1,3);
       // 第二页:显示3条数据
       //PageHelper.startPage(2,3);
       // 第三页:显示3条数据
       PageHelper.startPage(3,3);

       //5.调用实现类的方法,接收结果
       List<Student> list = mapper.selectAll();

       //6.处理结果
       for (Student student : list) {
           System.out.println(student);
      }
       //7.释放资源
       sqlSession.close();
       is.close();
  }
}

3.3 分页插件的参数获取

  • PageInfo:封装分页相关参数的功能类

  • 核心方法:

 

 

  • 测试:修改Test01代码,在释放资源以前,增长以下代码:

//其余分页的数据
PageInfo<User> pageInfo = new PageInfo<User>(list);
System.out.println("总条数:"+pageInfo.getTotal());
System.out.println("总页数:"+pageInfo.getPages());
System.out.println("当前页:"+pageInfo.getPageNum());
System.out.println("每页显示长度:"+pageInfo.getPageSize());
System.out.println("是否第一页:"+pageInfo.isIsFirstPage());
System.out.println("是否最后一页:"+pageInfo.isIsLastPage());

3.4 分页插件知识小结

  • 分页:能够将不少条结果进行分页显示

  • 分页插件 jar 包: pagehelper-5.1.10.jar 、 jsqlparser-3.1.jar

  • <plugins>:集成插件标签

  • 分页助手相关 API

    • PageHelper:分页助手功能类:

      1. startPage():设置分页参数

    • PageInfo:分页相关参数功能类:

      1. getTotal():获取总条数

      2. getPages():获取总页数

      3. getPageNum():获取当前页

      4. getPageSize():获取每页显示条数

      5. getPrePage():获取上一页

      6. getNextPage():获取下一页

      7. isIsFirstPage():获取是不是第一页

      8. isIsLastPage():获取是不是最后一页

四.MyBatis的多表操做 ***

4.1 多表模型介绍

  • 咱们以前学习的都是基于单表操做的,而实际开发中,随着业务难度的加深,确定须要多表操做的

  • 多表模型分类

    • 一对一:在任意一方创建外键,关联对方的主键

    • 一对多:在多的一方创建外键,关联一的一方的主键

    • 多对多:借助中间表,中间表至少两个字段,分别关联两张表的主键

4.2 多表模型一对一操做

  • 一对一模型: 人和身份证,一我的只有一个身份证

     

     

  • 代码实现

    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);
    • 老师在视频中拖出这两张表的关系图以下:

       

       

    • 看到的怎么是一对多呢?这是由于外键pid并无设置惟一约束,若是外键不是惟一,那就是容许重复,若是外键能够重复,那就是一对多

    • 因此若是想看到1:1的效果,那就须要给pid增长一个约束unique

    1. 建立项目mybatis03

     

     

    • jdbc.properties

      driver=com.mysql.jdbc.Driver
      url=jdbc:mysql://192.168.59.143:3306/db2
      username=root
      password=itheima
    • 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 核心根标签-->
      <configuration>
      
          <!--引入数据库链接的配置文件-->
          <properties resource="jdbc.properties"/>
      
          <!--配置LOG4J-->
          <settings>
              <setting name="logImpl" value="log4j"/>
          </settings>
      
          <!--起别名-->
          <typeAliases>
              <package name="com.itheima.bean"/>
          </typeAliases>
      
          <!--environments配置数据库环境,环境能够有多个。default属性指定使用的是哪一个-->
          <environments default="mysql">
              <!--environment配置数据库环境  id属性惟一标识-->
              <environment id="mysql">
                  <!-- transactionManager事务管理。  type属性,采用JDBC默认的事务-->
                  <transactionManager type="JDBC"></transactionManager>
                  <!-- dataSource数据源信息   type属性 链接池-->
                  <dataSource type="POOLED">
                      <!-- property获取数据库链接的配置信息 -->
                      <property name="driver" value="${driver}" />
                      <property name="url" value="${url}" />
                      <property name="username" value="${username}" />
                      <property name="password" value="${password}" />
                  </dataSource>
              </environment>
          </environments>
      
          <!-- mappers引入映射配置文件 -->
          <mappers>
          </mappers>
      </configuration>
    • log4j.properties

      # Global logging configuration
      # ERROR WARN INFO DEBUG
      log4j.rootLogger=DEBUG, stdout
      # Console output...
      log4j.appender.stdout=org.apache.log4j.ConsoleAppender
      log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
      log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
    1. javabean:card

      package com.itheima.bean;
      
      public class Card {
          private Integer id;     //主键id
          private String number;  //身份证号
      
          private Person p;       //所属人的对象 *** 在表中是外键pid:人id,可是在javabean中通常都是外键对应的实体类javabean
      
          public Card() {
          }
      
          public Card(Integer id, String number, Person p) {
              this.id = id;
              this.number = number;
              this.p = p;
          }
      
          public Integer getId() {
              return id;
          }
      
          public void setId(Integer id) {
              this.id = id;
          }
      
          public String getNumber() {
              return number;
          }
      
          public void setNumber(String number) {
              this.number = number;
          }
      
          public Person getP() {
              return p;
          }
      
          public void setP(Person p) {
              this.p = p;
          }
      
          @Override
          public String toString() {
              return "Card{" +
                      "id=" + id +
                      ", number='" + number + '\'' +
                      ", p=" + p +
                      '}';
          }
      }
    1. javabean:person

      package com.itheima.bean;
      
      public class Person {
          private Integer id;     //主键id
          private String name;    //人的姓名
          private Integer age;    //人的年龄
      
          public Person() {
          }
      
          public Person(Integer id, String name, Integer age) {
              this.id = id;
              this.name = name;
              this.age = age;
          }
      
          public Integer getId() {
              return id;
          }
      
          public void setId(Integer id) {
              this.id = id;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public Integer getAge() {
              return age;
          }
      
          public void setAge(Integer age) {
              this.age = age;
          }
      
          @Override
          public String toString() {
              return "Person{" +
                      "id=" + id +
                      ", name='" + name + '\'' +
                      ", age=" + age +
                      '}';
          }
      }
    1. 配置文件:新建com.itheima.one_to_one.OneToOneMapper.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="com.itheima.table01.OneToOneMapper">
          <!--配置字段和实体对象属性的映射关系
      	type指定要配置的实体对象是哪一个:card
      	-->
          <resultMap id="oneToOne" type="card">
              <!--id配置主键列:将sql中查询的cid列与card实体类中的id进行关联 -->
              <id column="cid" property="id" />
              <!--result配置非主键列-->
              <result column="number" property="number" />
              <!--
                  association:配置被包含对象的映射关系
                  property:被包含对象的变量名(属性名,在Card实体类中有一个p属性)
                  javaType:被包含对象的数据类型(直接给person别名,由于咱们经过typeAliases统一设置了bean包下全部实体类的别名了)
              -->
              <association property="p" javaType="person">
                  <id column="pid" property="id" />
                  <result column="name" property="name" />
                  <result column="age" property="age" />
              </association>
          </resultMap>
      	<!--resultMap属性指定的是resultMap标签的id
      	查询出来的结果涉及到两张表,因此不能使用resultType了
      	-->
          <select id="selectAll" resultMap="oneToOne">
              SELECT c.id cid,number,pid,NAME,age FROM card c,person p WHERE c.pid=p.id
          </select>
      </mapper>
    • 如何肯定谁包含了谁?哪一个是被包含对象?

    • 经过javabean的关联属性:

    • 在Card表中有一个关联属性P,那么Card就包含了Person

    1. MyBatisConfig.xml中配置映射文件:

      <mappers>
          <mapper resource="com/itheima/one_to_one/OneToOneMapper.xml"/>
      </mappers>
    1. 接口com.itheima.table01.OneToOneMapper

      package com.itheima.table01;
      
      import com.itheima.bean.Card;
      
      import java.util.List;
      
      public interface OneToOneMapper {
          //查询所有
          public abstract List<Card> selectAll();
      }
      
    1. 测试类:com.itheima.table01.Test01;

      package com.itheima.table01;
      
      import com.itheima.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.Test;
      
      import java.io.InputStream;
      import java.util.List;
      
      public class Test01 {
          @Test
          public void selectAll() throws Exception{
              //1.加载核心配置文件
              InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
      
              //2.获取SqlSession工厂对象
              SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
      
              //3.经过工厂对象获取SqlSession对象
              SqlSession sqlSession = sqlSessionFactory.openSession(true);
      
              //4.获取OneToOneMapper接口的实现类对象
              OneToOneMapper mapper = sqlSession.getMapper(OneToOneMapper.class);
      
              //5.调用实现类的方法,接收结果
              List<Card> list = mapper.selectAll();
      
              //6.处理结果
              for (Card c : list) {
                  System.out.println(c);
              }
      
              //7.释放资源
              sqlSession.close();
              is.close();
          }
      }
    1. 结果:

       

       

  • 一对一配置总结:

<resultMap>:配置字段和对象属性的映射关系标签。
    id 属性:惟一标识
    type 属性:实体对象类型
<id>:配置主键映射关系标签。
<result>:配置非主键映射关系标签。
    column 属性:表中字段名称
    property 属性: 实体对象变量名称
<association>:配置被包含对象的映射关系标签。
    property 属性:被包含对象的变量名
    javaType 属性:被包含对象的数据类型
  • 分析图

     

     

4.3 多表模型一对多操做

  • 一对多模型: 一对多模型:班级和学生,一个班级能够有多个学生

 

 

  • 代码实现

    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);
    1. 新建javabean:classes

      package com.itheima.bean;
      
      import java.util.List;
      
      public class Classes {
          private Integer id;     //主键id
          private String name;    //班级名称
      
          private List<Student> students; //班级中全部学生对象*** 一个班级里多个学生
      
          public Classes() {
          }
      
          public Classes(Integer id, String name, List<Student> students) {
              this.id = id;
              this.name = name;
              this.students = students;
          }
      
          public Integer getId() {
              return id;
          }
      
          public void setId(Integer id) {
              this.id = id;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public List<Student> getStudents() {
              return students;
          }
      
          public void setStudents(List<Student> students) {
              this.students = students;
          }
      
          @Override
          public String toString() {
              return "Classes{" +
                      "id=" + id +
                      ", name='" + name + '\'' +
                      ", students=" + students +
                      '}';
          }
      }
      
    1. javabean:student

      package com.itheima.bean;
      
      import java.util.List;
      
      public class Student {
          private Integer id;     //主键id
          private String name;    //学生姓名
          private Integer age;    //学生年龄
      
          public Student() {
          }
      
          public Student(Integer id, String name, Integer age) {
              this.id = id;
              this.name = name;
              this.age = age;
          }
      
          public Integer getId() {
              return id;
          }
      
          public void setId(Integer id) {
              this.id = id;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public Integer getAge() {
              return age;
          }
      
          public void setAge(Integer age) {
              this.age = age;
          }
      
          @Override
          public String toString() {
              return "Student{" +
                      "id=" + id +
                      ", name='" + name + '\'' +
                      ", age=" + age +
                      '}';
          }
      }
      
    1. 配置文件:com.itheima.one_to_many.OneToManyMapper.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="com.itheima.table02.OneToManyMapper">
          <resultMap id="oneToMany" type="classes">
              <id column="cid" property="id"/>
              <result column="cname" property="name"/>
      
              <!--
                  collection:配置被包含的集合对象映射关系(若是被包含的对象是多的一方,须要用collection)
                  property:被包含对象的变量名
                  ofType:被包含对象的实际数据类型(collection标签中指定被包含对象类型用的是ofType)
              -->
              <collection property="students" ofType="student">
                  <id column="sid" property="id"/>
                  <result column="sname" property="name"/>
                  <result column="sage" property="age"/>
              </collection>
          </resultMap>
          <select id="selectAll" resultMap="oneToMany">
              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
          </select>
      </mapper>
    1. 配置映射文件

       <mappers>
           <mapper resource="com/itheima/one_to_one/OneToOneMapper.xml"/>
           <mapper resource="com/itheima/one_to_many/OneToManyMapper.xml"/>
      </mappers>
    1. 接口

      package com.itheima.table02;
      
      import com.itheima.bean.Classes;
      
      import java.util.List;
      
      public interface OneToManyMapper {
          //查询所有
          public abstract List<Classes> selectAll();
      }
      
    1. 测试类com.itheima.table02.Test01

      package com.itheima.table02;
      
      import com.itheima.bean.Classes;
      import com.itheima.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.Test;
      
      import java.io.InputStream;
      import java.util.List;
      
      public class Test01 {
          @Test
          public void selectAll() throws Exception{
              //1.加载核心配置文件
              InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
      
              //2.获取SqlSession工厂对象
              SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
      
              //3.经过工厂对象获取SqlSession对象
              SqlSession sqlSession = sqlSessionFactory.openSession(true);
      
              //4.获取OneToManyMapper接口的实现类对象
              OneToManyMapper mapper = sqlSession.getMapper(OneToManyMapper.class);
      
              //5.调用实现类的方法,接收结果
              List<Classes> classes = mapper.selectAll();
      
              //6.处理结果
              for (Classes cls : classes) {
                  System.out.println(cls.getId() + "," + cls.getName());
                  List<Student> students = cls.getStudents();
                  for (Student student : students) {
                      System.out.println("\t" + student);
                  }
              }
      
              //7.释放资源
              sqlSession.close();
              is.close();
          }
      }
    1. 结果:

       

       

  • 一对多配置文件总结:

<resultMap>:配置字段和对象属性的映射关系标签。
    id 属性:惟一标识
    type 属性:实体对象类型
<id>:配置主键映射关系标签。
<result>:配置非主键映射关系标签。
    column 属性:表中字段名称
    property 属性: 实体对象变量名称
<collection>:配置被包含集合对象的映射关系标签。
    property 属性:被包含集合对象的变量名
    ofType 属性:集合中保存的对象数据类型
  • 分析图:

     

     

4.4 多表模型多对多操做

  • 多对多模型:学生和课程,一个学生能够选择多门课程、一个课程也能够被多个学生所选择

 

 

  • 代码实现

    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 stu_cr(
      	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 stu_cr VALUES (NULL,1,1);
      INSERT INTO stu_cr VALUES (NULL,1,2);
      INSERT INTO stu_cr VALUES (NULL,2,1);
      INSERT INTO stu_cr VALUES (NULL,2,2);
    1. Javabean

      package com.itheima.bean;
      
      public class Course {
          private Integer id;     //主键id
          private String name;    //课程名称
      
          public Course() {
          }
      
          public Course(Integer id, String name) {
              this.id = id;
              this.name = name;
          }
      
          public Integer getId() {
              return id;
          }
      
          public void setId(Integer id) {
              this.id = id;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          @Override
          public String toString() {
              return "Course{" +
                      "id=" + id +
                      ", name='" + name + '\'' +
                      '}';
          }
      }
    1. 修改:Student

       private List<Course> courses;   // 学生所选择的课程集合
        public Student(Integer id, String name, Integer age, List<Course> courses) {
              this.id = id;
              this.name = name;
              this.age = age;
              this.courses = courses;
          }
           public List<Course> getCourses() {
              return courses;
          }
      
          public void setCourses(List<Course> courses) {
              this.courses = courses;
          }
    2. 咱们这里只是多表查询,不作其余操做,因此中间表不须要对应的实体类

    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.itheima.table03.ManyToManyMapper">
          <resultMap id="manyToMany" type="student">
              <id column="sid" property="id"/>
              <result column="sname" property="name"/>
              <result column="sage" property="age"/>
      
              <collection property="courses" ofType="course">
                  <id column="cid" property="id"/>
                  <result column="cname" property="name"/>
              </collection>
          </resultMap>
          <select id="selectAll" resultMap="manyToMany">
              SELECT sc.sid,s.name sname,s.age sage,sc.cid,c.name cname FROM student s,course c,stu_cr sc WHERE sc.sid=s.id AND sc.cid=c.id
          </select>
          <!--注意这里查询的是sc.cid,将这个cid给course的id了,这也是能够的,由于都是课程id
      		但其实sql语句中的sc.cid,能够换成c.id,这样的话给course的id更合适	
      	-->
      </mapper>
    1. 配置

       <mappers>
              <mapper resource="com/itheima/one_to_one/OneToOneMapper.xml"/>
              <mapper resource="com/itheima/one_to_many/OneToManyMapper.xml"/>
              <mapper resource="com/itheima/many_to_many/ManyToManyMapper.xml"/>
          </mappers>
    1. 接口

      package com.itheima.table03;
      
      import com.itheima.bean.Student;
      
      import java.util.List;
      
      public interface ManyToManyMapper {
          //查询所有
          public abstract List<Student> selectAll();
      }
      
    1. 测试类

      package com.itheima.table03;
      
      import com.itheima.bean.Course;
      import com.itheima.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.Test;
      
      import java.io.InputStream;
      import java.util.List;
      
      public class Test01 {
          @Test
          public void selectAll() throws Exception{
              //1.加载核心配置文件
              InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
      
              //2.获取SqlSession工厂对象
              SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
      
              //3.经过工厂对象获取SqlSession对象
              SqlSession sqlSession = sqlSessionFactory.openSession(true);
      
              //4.获取ManyToManyMapper接口的实现类对象
              ManyToManyMapper mapper = sqlSession.getMapper(ManyToManyMapper.class);
      
              //5.调用实现类的方法,接收结果
              List<Student> students = mapper.selectAll();
      
              //6.处理结果
              for (Student student : students) {
                  System.out.println(student.getId() + "," + student.getName() + "," + student.getAge());
                  List<Course> courses = student.getCourses();
                  for (Course cours : courses) {
                      System.out.println("\t" + cours);
                  }
              }
      
              //7.释放资源
              sqlSession.close();
              is.close();
          }
      }
    1. 结果

       

       

  • 多对多配置文件总结:

<resultMap>:配置字段和对象属性的映射关系标签。
	id 属性:惟一标识
	type 属性:实体对象类型
 <id>:配置主键映射关系标签。
 <result>:配置非主键映射关系标签。
	column 属性:表中字段名称
	property 属性: 实体对象变量名称
<collection>:配置被包含集合对象的映射关系标签。
	property 属性:被包含集合对象的变量名
	ofType 属性:集合中保存的对象数据类型
  • 分析图

     

     

4.5 多表模型操做总结

 

相关文章
相关标签/搜索