• 【SSM】Mybatis01


    1. 初识Mybatis

    Mybatis简介

    Mybatis是一个半自动的持久化层ORM框架

    • 半自动化:Mybatis与Hibernate对比

      • Mybatis是一个半自动框架【需要手写SQL,为SQL优化提供了可能。】
      • Hibernate是全自动化【无需手写SQL】
    • 持久化层:
      数据可以持久化,将数据不仅仅放在内存中,而是保存在数据库中。也就是我们常说的DAO层。Mybatis可以帮助我们更方便地从数据库中取出数据、插入数据等。

    • ORM框架:遵循对象关系映射。

    • Mybatis与JDBC的对比

      • JDBC中SQL与java代码耦合度高。
      • Mybatis将SQL与java代码解耦。

    2. 搭建Mybatis框架

    • 准备工作
      • 创建数据库(这里以Employee表为例)
        在这里插入图片描述
      • 准备Maven工程
        关于Maven工程的创建可以参考我的上一篇文章。

    框架搭建

    1. 使用maven导入jar包。
    <dependencies>
            
            <dependency>
                <groupId>org.mybatisgroupId>
                <artifactId>mybatisartifactId>
                <version>3.5.6version>
            dependency>
            
            <dependency>
                <groupId>junitgroupId>
                <artifactId>junitartifactId>
                <version>4.12version>
                <scope>testscope>
            dependency>
    
            
            <dependency>
                <groupId>mysqlgroupId>
                <artifactId>mysql-connector-javaartifactId>
                <version>8.0.28version>
            dependency>
        dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    1. 编写核心配置文件
      • 位置:resources

      • 名称:推荐使用mybatis-config.xml

      • 示例代码

       
       DOCTYPE configuration
               PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
               "http://mybatis.org/dtd/mybatis-3-config.dtd">
       <configuration>
           <environments default="development">
               <environment id="development">
                   <transactionManager type="JDBC"/>
                   <dataSource type="POOLED">
                       <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                       <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8"/>
                       <property name="username" value="root"/>
                       <property name="password" value="root"/>
                   dataSource>
               environment>
           environments>
           <mappers>
               <mapper resource="mapper/EmployeeMapper.xml"/>
           mappers>
       configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    1. 编写POJO、接口。
      现在创建普通java对象pojo。之后创建mapper映射,即编写与数据库交互的接口。我们先添加一个:selectEmyById。下面我们通过写映射文件与数据库进行交互。不需要我们手写DAO了。
      当前结构如图所示:在这里插入图片描述
    2. 书写映射文件
    • 映射文件作用:主要作用为Mapper接口书写Sql语句

    • 映射文件位置:resources/mapper名称:XXXMapper.xml,与接口名一致。

    • 示例代码

    
    DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    		
    <mapper namespace="mybatis.mapper.EmployeeMapper">
        	
        <select id="selectEmpById" resultType="mybatis.pojo.Employee">
            SELECT
                id,last_name 'lastName' ,email,salary
            FROM
                tbl_employee
            WHERE
                id = #{id}
        select>
    mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    注意:

    SELECT语句中查询的属性名应该与Employee的属性一致(使用别名),如果不一致,可能出现最终查询值为null的情况。后面可以通过设置标签,来避免设置别名的情况。

    1. 测试程序
    • 示例代码
    	//1. 获取到sqlSessionFactory
    	String resource = "mybatis-config.xml";
    	InputStream inputStream = Resources.getResourceAsStream(resource);
    	SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    	//2. 使用sqlSessionFactory获取sqlSession
    	SqlSession sqlSession = sqlSessionFactory.openSession();
    	//3. 获取EmployeeMapper的代理对象【com.sun.proxy.$Proxy6】
    	EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
    	System.out.println("employeeMapper.getClass().getName() = " + employeeMapper.getClass().getName());
    	
    	Employee employee = employeeMapper.selectEmpById(1);
    	System.out.println("employee = " + employee);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    添加Log4j日志框架

    • 使用maven导入jar包
      
      <dependency>
          <groupId>log4jgroupId>
          <artifactId>log4jartifactId>
          <version>1.2.17version>
      dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 编写配置文件
      • 配置文件位置:resources
      • 配置文件名称:log4j.xml
      • 示例代码
        
        DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
        
        <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
        
            <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
                <param name="Encoding" value="UTF-8" />
                <layout class="org.apache.log4j.PatternLayout">
                    <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m  (%F:%L) \n" />
                layout>
            appender>
            <logger name="java.sql">
                <level value="debug" />
            logger>
            <logger name="org.apache.ibatis">
                <level value="info" />
            logger>
            <root>
                <level value="debug" />
                <appender-ref ref="STDOUT" />
            root>
        log4j:configuration>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22

    3. Mybatis核心配置文件解析【Mybatis-config.xml】

    MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。

    • configuration:根标签,没有实际语义,所有子标签需要设置在根标签内部。

    • properties:定义或引入外部属性文件。实现代码与数据库连接的解耦。

      • 示例代码
      
      DOCTYPE configuration
              PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
              "http://mybatis.org/dtd/mybatis-3-config.dtd">
      <configuration>
      
          <properties resource="db.properties">
          properties>
          <environments default="development">
              <environment id="development">
                  <transactionManager type="JDBC"/>
                  <dataSource type="POOLED">
                      <property name="driver" value="${driver}"/>
                      <property name="url" value="${url}"/>
                      <property name="username" value="${username}"/>
                      <property name="password" value="${password}"/>
                  dataSource>
              environment>
          environments>
          <mappers>
              <mapper resource="mapper/EmployeeMapper.xml"/>
          mappers>
      configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    	  //编写配置文件——db.properties
    	  driver=com.mysql.cj.jdbc.Driver
    	  url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8
    	  username=root
    	  password=root
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • settings:这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。
      比如:mapUnderscoreToCamelCase:是否开启驼峰命名自动映射。默认值false,如设置true会自动将last_name对应到lastName。

      • 示例代码
      <settings>
          <setting name="mapUnderscoreToCamelCase" value="true"/>
      settings>
      
      • 1
      • 2
      • 3
    • typeAliases:类型别名可为 Java 类型设置一个缩写名字。

      • 示例代码

        <typeAliases>
        
        <typeAlias type="mybatis.pojo.Employee" alias="employee">
        typeAlias>
        
        <package name="mybatis.pojo"/>
        typeAliases>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
      • Mybatis自定义别名

        别名类型
        _intint
        integer或intInteger
        stringString
        list或arraylistArrayList
        map或hashmapHashMap
    • environments:设置数据库连接环境。

    • mappers:设置映射文件路径

      • 示例代码

        <mappers>
            
                <mapper resource="mapper/EmployeeMapper.xml"/>
            
                
               <package name="mybatis.mapper"/>
            mappers>
        
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8

      注意:
      核心配置中的子标签,是有顺序要求的。

      在这里插入图片描述

    4. Mybatis映射文件详解【XXXMapper.xml】

    MyBatis 的真正强大在于它的语句映射,这是它的魔力所在。如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。

    映射文件中的标签

    • 根标签

      • mapper:mapper中的namespace要求与接口的全类名一致。
    • 子标签

      • insert标签:定义添加SQL
      • delete标签:定义删除SQL
      • update标签:定义修改SQL
      • select标签:定义查询SQL
      • sql标签:定义可重用的SQL语句块
      • cache标签:设置当前命名空间的缓存配置
      • cache-ref标签:设置其他命名空间的缓存配置
      • resultType标签:设置期望结果集返回类型【全类名或别名】
        • 如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。
        • resultType 和 resultMap 之间只能同时使用一个。
      • resultMap标签: 描述如何从数据库结果集中加载对象
        • resultType解决不了的问题(比如多表查询时,返回多个结果集),使用resultMap。

    获取主键自增数据

    useGeneratedKeys标签:获取主键自增的属性—true,配合keyProperty标签:设置存储属性值。

    <insert id="InsertEmp" useGeneratedKeys="true"
        keyProperty="id">
    	INSERT INTO
                tbl_employee(last_name,email,salary)
            	VALUES(#{lastName},#{email},#{salary});
        insert>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    获取数据库受影响行数

    直接让接口中的方法返回一个值即可。

    • int:返回对数据库影响行数。
    • boolean:返回对数据库是否有影响。

    5. Mbatis中参数传递问题

    这一部分我们主要讲编写在映射文件中的SQL,所传入的参数问题。

    INSERT INTO
     tbl_employee(last_name,email,salary)
    VALUES(#{lastName},#{email},#{salary})
    
    • 1
    • 2
    • 3

    单个普通参数

    可以任意使用,不需要考虑数据类型和参数名称。

    多个普通参数

    Mybatis底层会封装成Map,key为param1、param2 或者 arg0、arg1。
    传入多个普通参数时,有两个办法:

    1. 直接在参数传递处写param即可。

    2. 命名参数:在接口处的形参之前,加上注解

      • 代码示例
      public void Update(@Param("id") int id, @Param("lastName") String lastName);
      
      • 1

      命名参数底层源码分析:

      • 源码分析

        • MapperMethod对象:142行代码【命名参数底层代码入口】
        • 命名参数底层封装map为ParamMap,ParamMap继承HashMap
        • ParamNameResolver对象:130行代码,命名参数底层实现逻辑
      //130行
      final Map<String, Object> param = new ParamMap<>();
      int i = 0;
      for (Map.Entry<Integer, String> entry : names.entrySet()) {
        param.put(entry.getValue(), args[entry.getKey()]);
        // add generic param names (param1, param2, ...)
        final String genericParamName = GENERIC_NAME_PREFIX + (i + 1);
        // ensure not to overwrite parameter named with @Param
          //支持param1、param2的逻辑
        if (!names.containsValue(genericParamName)) {
          param.put(genericParamName, args[entry.getKey()]);
        }
        i++;
      }
      return param;
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
    3. POJO参数
      当接口处的参数属于pojo时,可以直接传入pojo。其参数传递处为pojo属性名。

    4. Map参数
      当接口处的参数属于Map时,直接使用Map入参,Map的key即为传入的参数。value为传入的值。

    5. Collection|List|Array等参数
      参数名:collection、list、array

    参数传递中#与$的区别

    • 【#】:底层执行SQL使用PreparedStatement对象,入参使用SQL拼接方式,预编译SQL,相对安全。

    • 【$】:底层执行SQL使用Statement对象,入参使用占位符方式,存在SQL注入问题。

    查询SQL:
    SELECT col1,col2
    FROM table1
    WHERE col = ? AND col2 = ?
    ​GROUP BY ? , ORDER BY ? , LIMIT ? , ? ;

    • #:sql占位符位置均可以使用# 。
    • $:其余位置使用。比如FROM中的动态化表名。

    6. Select查询返回结果的几种情况

    • 查询单行数据返回单行结果

      示例代码:

      //根据id获取雇员信息。
          public Employee selectEmpById (int id);
      
      • 1
      • 2
      <select id="selectEmpById" resultType="mybatis.pojo.Employee">
              SELECT
                  id,last_name ,email,salary
              FROM
                  tbl_employee
              WHERE
                  id = #{id}
          select>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    • 查询多行数据返回对象集合

      如果返回的是集合,resultType应该设置为集合包含的类型,而不是集合本身的类型。

      示例代码:

      public List<Employee> selectTbl(String tblName);
      
      • 1
      <select id="selectTbl" resultType="mybatis.pojo.Employee">
            SELECT
                id,last_name ,email,salary
            FROM
                ${tblName}
        select>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
    • 查询单行数据返回Map集合

      Map:字段作为Map的key,查询结果作为Map的Value。
      示例代码:

       /**
           * 查询单行数据返回Map集合
           */
      public Map<String,Object> selectEmpReturnMap (int id);
      
      • 1
      • 2
      • 3
      • 4
      <select id="selectEmpReturnMap" resultType="map">
              SELECT
                  id,last_name,email,salary
              FROM
                  tbl_employee
              WHERE
                  id = #{id}
          select>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    • 查询多行数据返回Map集合
      Map:对象id作为key,对象本身作为value。
      示例代码:

      /**
      * 查询多行数据返回Map
      * Map
      * Map
      *      对象Id作为:key
      *      对象作为:value
      * @return
      */
      @MapKey("id")
      public Map<Integer,Employee> selectEmpsReturnMap();
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      <select id="selectEmpsReturnMap" resultType="map">
        SELECT
            id,
            last_name,
            email,
            salary
        FROM
            tbl_employee
      select>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9

    7. Mybatis中的自动映射与自定义映射

    自动映射/自定义映射可以在映射文件【XXXMapper.xml】中进行配置。

    • 自动映射:resultType
      即自动将表中的字段与类中的属性进行关联映射。后面接SQL所查询POJO类的全类名。

    • 自定义映射:resultMap
      当resultType解决不了的问题时,使用resultMap:

      1. 属性名和字段名未对应,不采取驼峰式自动命名和别名的形式。
      2. 多表查询问题时,此时返回类型较为复杂。

    ResultMap相关标签及属性

    • resultMap标签:自定义映射标签

      • id属性:定义唯一标识
      • type属性:设置映射类型
    • resultMap子标签

      • id标签:定义主键字段与属性关联关系

      • result标签:定义非主键字段与属性关联关系

        • column属性:定义表中字段名称
        • property属性:定义类中属性名称
      • association标签:定义一对一的关联关系

        • property:定义关联关系属性(类的属性名)
        • javaType:定义关联关系属性的类型(全类名)
        • select:设置分步查询的SQL所在的全路径
        • colunm:设置分步查询的SQL中需要的参数(字段名)
        • fetchType:设置局部延迟加载【懒加载】是否开启
      • collection标签:定义一对多的关联关系

        • property:定义关联关系属性(类的属性名)
        • ofType:定义关联关系属性的类型(全类名)
        • select:设置分步查询的SQL所在的全路径
        • colunm:设置分步查询的SQL中需要的参数(字段名)
        • fetchType:设置局部延迟加载【懒加载】是否开启

    自定义映射

    级联映射
    <resultMap id="EmpAndDepResultMap" type="employee">
    
            <id column="id" property="id">id>
    
            <result column="last_name" property="lastName">result>
            <result column="email" property="email">result>
            <result column="salary" property="salary">result>
    
            <result column="dept_id" property="dept.deptId">result>
            <result column="dept_name" property="dept.deptName">result>
        resultMap>
        <select id="selectEmpAndDptById" resultMap="EmpAndDepResultMap">
            SELECT e.email,
                   e.id,
                   e.last_name,
                   e.salary,
                   d.dept_id,
                   d.dept_name
            FROM
                tbl_employee e
            JOIN
                    tbl_dept d
            ON
                e.dept_id  = d.dept_id
            WHERE
                e.id = #{id}
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    association映射
    • 特点:解决一对一映射关系(一个员工对应一个部门)
    <resultMap id="EmpAndDepResultMap01" type="employee">
            
            <id column="id" property="id">id>
            
            <result column="last_name" property="lastName">result>
            <result column="email" property="email">result>
            <result column="salary" property="salary">result>
    
            <association property="dept" javaType="Mybatis.pojo.Dept">
                <id column="dept_id" property="deptId">id>
                <result column="dept_name" property="deptName">result>
            association>
        resultMap>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    collection映射
    • 定义一对多的映射关系(一个部门对应多个员工)
    <resultMap id="selectDepAndEmpByIdResultMap" type="dept">
            <id property="deptId" column="dept_id">id>
            <result property="deptName" column="dept_name">result>
            
            <collection property="empList"
                        ofType="Mybatis.pojo.Employee">
                <id column="id" property="id">id>
                <result column="last_name" property="lastName">result>
                <result column="email" property="email">result>
                <result column="salary" property="salary">result>
            collection>
    resultMap>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    8. 延迟加载【懒加载】

    • 需要即加载,不需要暂时不加载

    • 优势:提升程序运行效率

      • 全局设置

        
        <setting name="lazyLoadingEnabled" value="true"/>
        
        <setting name="aggressiveLazyLoading" value="false"/>
        
        • 1
        • 2
        • 3
        • 4
      • 局部设置

        • collection、association中的fetchType标签
          • eager:关闭局部延迟加载
          • lazy:开启局部延迟加载

    9. 分步查询

    • 为什么使用分步查询?

      • 将多表连接查询,改为【分步单表查询】,从而提高程序运行效率
    • 示例代码(一对一)

      EmployeeMapper
      /**
       * 通过员工id获取员工信息及员工所属的部门信息【分步查询】
              1. 先通过员工id获取员工信息【id、last_name、email、salary、dept_id】
       */
      public Employee selectEmpAndDeptByEmpIdAssociationStep(int empId);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      DeptMapper
      //2. 再通过部门id获取部门信息【dept_id、dept_name】
          public Dept selectDeptById(int id);
      
      • 1
      • 2
      • 3
      EmployeeMapper.xml
      <resultMap id="EmpAndDepResultMap02" type="employee">
              <id column="id" property="id">id>
              <result column="last_name" property="lastName">result>
              <result column="email" property="email">result>
              <result column="salary" property="salary">result>
      
              <association property="dept"
                           select="Mybatis.mapper.DeptMapper.selectDeptById"
                           column="dept_id">
              association>
          resultMap>
          <select id="selectEmpAndDeptByEmpIdAssociationStep" resultMap="EmpAndDepResultMap02">
              select
                  id,
                  last_name,
                  email,
                  salary,
                  dept_id
              from
                  tbl_employee
              where
                  id=#{empId}
          select>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      DeptMapper.xml
      <select id="selectDeptById" resultType="dept">
              select
                  dept_id,
                  dept_name
              from
                  tbl_dept
              WHERE dept_id = #{id}
          select>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
    • 示例代码(一对多)
      通过部门id获取部门信息,及部门所属员工信息【分步查询】
      1. 通过部门id获取部门信息
      2. 通过部门id获取员工信息

      public Dept selectDeptAndEmpByDeptIdStep(int deptId);
    
    • 1
      
          <select id="selectDeptAndEmpByDeptIdStep" resultMap="deptAndEmpResultMapStep">
              select
                  dept_id,
                  dept_name
              from
                  tbl_dept
              where
                  dept_id=#{deptId}
          select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
      public List<Employee> selectEmpByDeptId(int deptId);
    
    • 1
    
      <select id="selectEmpByDeptId" resultType="employee">
          select
              id,
              last_name,
              email,
              salary,
              dept_id
          from
              tbl_employee
          where
              dept_id=#{deptId}
      select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    分步查询SQL中需要多个参数时,column封装为map。k=传入参数名 v=字段名。语法:{k1=v1,k2=v2}

    10. Mybatis的动态SQL

    动态SQL概述

    动态SQL即SQL语句可动态化。Mybatis的动态SQL中支持OGNL表达式语言,OGNL( Object Graph Navigation Language )对象图导航语言。

    动态SQL中的常用标签

    • if标签:用于完成简单的判断。

    • where标签:用于解决where关键字及where后第一个and或or的问题。

    • trim标签: 可以在条件判断完的SQL语句前后添加或者去掉指定的字符。

      • prefix: 添加前缀

      • prefixOverrides: 去掉前缀

      • suffix: 添加后缀

      • suffixOverrides: 去掉后缀

    • set标签:主要用于解决set关键字及多出一个【,】问题。

    • choose标签:类似java中if-else【switch-case】结构

    • foreach标签:类似java中增强for循环

      • collection: 要迭代的集合
      • item: 当前从集合中迭代出的元素
      • separator: 元素与元素之间的分隔符
      • open: 开始字符
      • close:结束字符
    • sql标签:提取可重用SQL片段

    示例代码

    • 演示if-where标签的使用,if 进行条件判断,where 解决and/or问题。

      
          <select id="selectEmpByOpr" resultType="employee">
              <include refid="select_employee">include>
              <where>
                  <if test="id != null">
                     and id = #{id}
                  if>
                  <if test="lastName != null">
                      and last_name = #{lastName}
                  if>
                  <if test="email != null">
                      and email = #{email}
                  if>
                  <if test="salary != null">
                      and salary = #{salary}
                  if>
              where>
          select>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
    • 演示trim标签的使用,解决前后缀问题。

          <select id="selectEmpByOprTrim" resultType="employee">
              <include refid="select_employee">include>
              <trim prefix="where" suffixOverrides="and">
                  <if test="id != null">
                      id = #{id} and
                  if>
                  <if test="lastName != null">
                      last_name = #{lastName} and
                  if>
                  <if test="email != null">
                      email = #{email} and
                  if>
                  <if test="salary != null">
                      salary = #{salary}
                  if>
              trim>
          select>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
    • 演示set标签的使用,解决问题

          <update id="updateEmpByOpr">
              update
                  tbl_employee
              <set>
                  <if test="lastName != null">
                      last_name=#{lastName},
                  if>
                  <if test="email != null">
                      email=#{email},
                  if>
                  <if test="salary != null">
                      salary=#{salary}
                  if>
              set>
              where
                  id = #{id}
          update>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
    • 演示choose标签,when相当于if-else,otherwise表示否则。

       <select id="selectEmpByOneOpr" resultType="employee">
              select
                  <include refid="emp_col">include>
              from
                  tbl_employee
              <where>
                  <choose>
                      <when test="id != null">
                          id = #{id}
                      when>
                      <when test="lastName != null">
                          last_name = #{lastName}
                      when>
                      <when test="email != null">
                          email = #{email}
                      when>
                      <when test="salary != null">
                          salary = #{salary}
                      when>
                      <otherwise>
                          1=1
                      otherwise>
                  choose>
              where>
          select>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
    • 演示foreach标签,解决查询多个id的循环问题。

      //foreach标签中的collection属性为集合,item属性为每次循环的对象
      	item    collection
      for(int id  :   ids){
          
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
          <select id="selectEmpByIds" resultType="employee">
              select
                  id,
                  last_name,
                  email,
                  salary
              from
                  tbl_employee
              <where>
                  id in(
                  <foreach collection="ids" item="id" separator=",">
                      #{id}
                  foreach>
                  )
              where>
      
          select>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
    • 使用foreach批量添加员工信息。

       <insert id="batchInsertEmp">
           INSERT INTO
               tbl_employee(last_name,email,salary)
           VALUES
               <foreach collection="employees" item="emp" separator=",">
                   (#{emp.lastName},#{emp.email},#{emp.salary})
               foreach>
       insert>
      mapper>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
    • sql标签的使用,提取重用的sql片段

      <sql id="emp_col">
              id,
              last_name,
              email,
              salary
          sql>
          <sql id="select_employee">
              select
                  id,
                  last_name,
                  email,
                  salary
              from
                  tbl_employee
          sql>
      
      
      <include refid="emp_col">include>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18

    11. Mybatis中的缓存机制

    Mybatis中的缓存

    • 使用缓存的优势

      1. 提高查询效率
      2. 降低服务器压力
    • 缓存的类型

      • 一级缓存
      • 二级缓存
      • 第三方缓存

    在这里插入图片描述

    一级缓存

    一级缓存,也叫做本地缓存(sqlSession级别的缓存)

    • 特点

      一级缓存默认开启,不能关闭,但是可以清空。

    • 缓存失效的情况

      1. 不同的sqlSession代表不同的一级缓存。

      2. 同一个sqlSession两次查询数据库进行增删改操作【默认清空了一级缓存】

      3. 同一个sqlSession但是查询条件不同。

      4. 同一个sqlSession两次查询期间手动清空了缓存。【 sqlSession.clearCache();

      5. 同一个sqlSession两次查询期间提交了事务。 【 sqlSession.commit();

    • 缓存原理

      1. 第一次获取数据时,先从数据库中加载数据,将数据缓存到Mybatis的一级缓存中。【底层使用Map实现,key:hashCode+查询的SqlId+编写的sql查询语句+参数】
      2. 以后再获取数据时,先从一级缓存中获取数据,如果数据失效,再从数据库中获取。
    二级缓存

    二级缓存,也叫全局作用域缓存(sqlSessionFactory缓存)。

    • 特点

      • 二级缓存默认关闭,需要开启才能使用。

      • 二级缓存需要提交sqlSession或关闭sqlSession时,才会缓存。

    • 二级缓存使用步骤

      1. 配置文件中开启二级缓存
      2. 需要使用二级缓存的映射文件处使用cache配置缓存
      3. POJO需要实现Serializable接口,实现属性UID。
      4. 关闭sqlSession或提交sqlSession时,将数据缓存到二级缓存。
    • 二级缓存相关属性

      在映射文件处的标签中配置。

      • eviction=“FIFO”:缓存清除【回收】策略。
        • LRU – 最近最少使用的:移除最长时间不被使用的对象。
        • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
      • flushInterval:刷新间隔,单位毫秒
      • size:引用数目,正整数
      • readOnly:只读,true/false
    • 二级缓存的失效情况

      • 在两次查询之间,执行增删改操作,会同时清空一级缓存和二级缓存。

      • sqlSession.clearCache():只是用来清除一级缓存。

    • 二级缓存底层原理

      • 第一次获取数据时,先从数据库中获取数据,将数据缓存至一级缓存;当提交或关闭SqlSession时,将数据缓存至二级缓存。

      • 以后再次获取数据时,先从一级缓存中获取数据,如一级缓存没有指定数据,再去二级缓存中获取数据。如二级缓存也没有指定数据时,需要去数据库中获取数据,…

    第三方缓存

    第三方缓存:EhCache,是一个纯Java的进程内缓存框架。

    • 使用步骤

      • maven中导入jar包

        
        <dependency>
            <groupId>org.mybatis.cachesgroupId>
            <artifactId>mybatis-ehcacheartifactId>
            <version>1.0.3version>
        dependency>
        
        
        <dependency>
            <groupId>org.slf4jgroupId>
            <artifactId>slf4j-log4j12artifactId>
            <version>1.6.2version>
            <scope>testscope>
        dependency>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
      • 编写配置文件【ehcache.xml】

        
        <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
            
            <diskStore path="D:\mybatis\ehcache" />
        
            <defaultCache
                    maxElementsInMemory="512"
                    maxElementsOnDisk="10000000"
                    eternal="false"
                    overflowToDisk="true"
                    timeToIdleSeconds="120"
                    timeToLiveSeconds="120"
                    diskExpiryThreadIntervalSeconds="120"
                    memoryStoreEvictionPolicy="LRU">
            defaultCache>
        ehcache>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
      • 加载第三方缓存到映射文件

      • 开始使用

    • 注意事项

      • 第三方缓存,需要建立在二级缓存基础上【需要开启二级缓存,第三方缓存才能生效】
      • 如何让第三方缓存失效【将二级缓存设置失效即可】

    12. Mybatis的逆向工程

    • 正向工程:应用程序中的代码影响数据库表中的数据。【java对象影响表】
    • 逆向工程:数据库中的表影响程序中的代码【表影响java对象(POJO、Mapper、Mapper.xml)】

    MBG

    Mybatis Generator:简称MBG,是一个专门为Mybatis框架使用者定制的代码生成器,可以快速的根据表生成对应的映射文件、接口、以及POJO类

    • 目前只可以生成单表CRUD【生成单表QBC风格CRUD】,表连接等复杂SQL需要手动解决。

    官方文档:MyBatis Generator Core – Introduction to MyBatis Generator

    MBG基本使用

    使用步骤:

    • 导入jar包

      
      <dependency>
          <groupId>org.mybatis.generatorgroupId>
          <artifactId>mybatis-generator-coreartifactId>
          <version>1.3.6version>
      dependency>
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    • 编写配置文件

      • 配置文件名称:mbg.xml
      • 配置文件位置:resources
      DOCTYPE generatorConfiguration PUBLIC
              "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
              "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
      <generatorConfiguration>
          
          <context id="simple" targetRuntime="MyBatis3Simple">
              
              <property name="javaFileEncoding" value="UTF-8"/>
      
      
              <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                              connectionURL="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8"
                              userId="root"
                              password="root">
      
                  
                  <property name="nullCatalogMeansCurrent" value="true" />
              jdbcConnection>
      
              <javaModelGenerator targetPackage="mybatis.pojo" targetProject="src/main/java"/>
      
              <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources"/>
      
              <javaClientGenerator type="XMLMAPPER" targetPackage="mybatis.mapper" targetProject="src/main/java"/>
      
      
              <table tableName="tbl_employee" domainObjectName="Employee" />
              <table tableName="tbl_dept" domainObjectName="Department"/>
      
          context>
      
      generatorConfiguration>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
    • 运行程序,即可检查生成的代码。

         List<String> warnings = new ArrayList<String>();
         boolean overwrite = true;
         File configFile = new File("generatorConfig.xml");
         ConfigurationParser cp = new ConfigurationParser(warnings);
         Configuration config = cp.parseConfiguration(configFile);
         DefaultShellCallback callback = new DefaultShellCallback(overwrite);
         MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
         myBatisGenerator.generate(null);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

    QBC风格

    Query By Criteria,根据标准查询。即条件都是定义好的,只需要调用相对应的方法,就可以生成标准的条件。

    实现QBC风格,只需要将配置文件中的:
    改为

    • 代码示例
    public void test1() {
        try {
            InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
            SqlSession sqlSession = factory.openSession(true);
            EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
            //创建条件对象
            EmpExample example = new EmpExample();
            // 给条件对象赋值对应的标准条件
            example.createCriteria().andEmpNameEqualTo("张三");
            // 在SQL语句中直接调用该对象
            List<Emp> empList = mapper.selectByExample(example);
            empList.forEach(emp -> System.out.println(emp));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    13. Mybatis的分页插件

    • 为什么要分页?
      • 提高用户体验。
      • 降低服务器端的压力。

    设计Page类

    回顾SQL语句: LIMIT(x,y)
    x就是开始的页数。y是每页显示的数量。

    如果要自己手动实现分页,则需要设计Page类。

    • pageNum:当前页码。
    • pages:总页数。
    • total:总数据数量。
    • pageSize:每页显示数据数量。
    • List:当前页显示数据集合。

    PageHelper分页插件

    PageHelper是Mybatis中非常方便的第三方分页插件。

    官方文档:Mybatis-PageHelper/README_zh.md at master · pagehelper/Mybatis-PageHelper · GitHub

    使用步骤:

    1. 导入jar包。

      
      <dependency>
          <groupId>com.github.pagehelpergroupId>
          <artifactId>pagehelperartifactId>
          <version>5.2.0version>
      dependency>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
    2. myabtis-config.xml中配置分页插件。

      <plugins>
      		
          <plugin interceptor="com.github.pagehelper.PageInterceptor">plugin>
      plugins>
      
      • 1
      • 2
      • 3
      • 4
    3. 查询之前,使用PageHelper开启分页。

      • pageHelper.startPage(1,3)——>(当前页码,每页的数据量)

      • 示例代码

        public void text() throws Exception{
                String resource = "mybatis-config.xml";
                InputStream inputStream = Resources.getResourceAsStream(resource);
                SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
                SqlSession sqlSession = sqlSessionFactory.openSession();
                EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        
                //使用分页
                Page<Object> page = PageHelper.startPage(1, 4);
        
                for (Employee employee : mapper.selectAll()) {
                    System.out.println(employee);
                }
                System.out.println(page.getPageNum() + "/" + page.getPages());
                System.out.println("总页数:"+ page.getPages());
                System.out.println("总数据量:" + page.getTotal());
                System.out.println("返回结果的集合"+page.getResult());
                for (Object o : page.getResult()) {
                    System.out.println("o = " + o);
                }
            }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
    4. 查询之后,可以使用更强大的PageInfo实现后续分页效果。

      public void text1() throws Exception{
              String resource = "mybatis-config.xml";
              InputStream inputStream = Resources.getResourceAsStream(resource);
              SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
              SqlSession sqlSession = sqlSessionFactory.openSession();
              EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
      
              //使用分页
              Page<Object> page = PageHelper.startPage(1, 4);
      
              List<Employee> employees = mapper.selectAll();
      
              //设置页码
              PageInfo<Employee> pageInfo = new PageInfo<>(employees,5);
          	//方法演示
              System.out.println("导航页的第一个页码:"+pageInfo.getNavigateFirstPage());
              System.out.println("导航页的最后一个页码:"+pageInfo.getNavigateLastPage());
              System.out.println("导航页的总页码:"+ pageInfo.getNavigatePages());
              /*
                  分页页码逻辑:
                  当前页码1:1 2 3 4 5
                  当前页码4:2 3 4 5 6
                  当前页码5:3 4 5 6 7
               */
              
          }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
  • 相关阅读:
    jmeter-函数助手,关联数据,CSV文件读取
    计算机毕业设计Javaweb家庭财务管理系统(源码+系统+mysql数据库+lw文档)
    【云原生 | 29】Docker运行大数据经典分布式平台Hadoop
    Multitor:一款带有负载均衡功能的多Tor实例创建工具
    使用 BERT 进行文本分类 (03/3)
    conan使用包以及管理(2)
    链表oj3(Leetcode)——相交链表;环形链表
    「免费申请」基于Arm Cortex-M4的兆易创新GD32F427高性能开发板试用活动
    “系统重要性银行”光环下,南京银行的重重忧思
    【状语从句练习题】主将从现原则
  • 原文地址:https://blog.csdn.net/weixin_62633072/article/details/126670152