ssm-Mybatis-全部知识点-胜哥

SSM框架【Spring+SpringMVC+Mybatis】

第一章 框架

1.1 生活中“框架”

  • 买楼房
  • 手抓饼
  • 使用笔记本电脑

1.2 程序中【框架】半成品

  • Mybatis:持久化层框架【dao-JDBC】
  • SpringMVC:表示层【表现层】,Servlet
  • Spring:全能

第二章 Mybatis 简介

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

  • ORM:Object Relation Mapping【对象 关系 映射】

    • 将JavaBean【JavaPOJO】与数据库中表建立映射关系,优势:只要操作POJO就会直接影响表中数据
  • Mybatis与Hibernate【持久化层框架】

    • Hibernate全自动持久化层框架
    • Mybatis半自动持久化层框架
  • Mybatis与JDBC

    • JDBC不足:Java与SQL代码耦合度较高
    • Mybatis优势:将Java代码与SQL解耦

第三章 Mybatis之Helloworld

导入jar包

编写配置文件

使用核心类库

3.1 搭建Mybatis框架步骤

  • 准备工作

    • 建库建表建约束
    • 建POJO【JavaBean】
  • 搭建环境

    • 导包

      <dependencies>
              <!--导入MyBatis的jar包-->
              <dependency>
                  <groupId>org.mybatis</groupId>
                  <artifactId>mybatis</artifactId>
                  <version>3.5.6</version>
              </dependency>
              <!--        Mysql驱动包-->
              <dependency>
                  <groupId>mysql</groupId>
                  <artifactId>mysql-connector-java</artifactId>
                  <version>5.1.37</version>
              </dependency>
              <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
      <!--        <dependency>-->
      <!--            <groupId>mysql</groupId>-->
      <!--            <artifactId>mysql-connector-java</artifactId>-->
      <!--            <version>8.0.16</version>-->
      <!--        </dependency>-->
      
              <!--junit-->
              <dependency>
                  <groupId>junit</groupId>
                  <artifactId>junit</artifactId>
                  <version>4.12</version>
                  <scope>test</scope>
              </dependency>
      
          </dependencies>
      
    • 编写核心配置文件【Mybatis常用设置】

      • 位置:resources目录下

      • 文件名:mybatis-config.xml

      • 示例代码

        <?xml version="1.0" encoding="UTF-8" ?>
        <!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.jdbc.Driver"/>
                        <property name="url" value="jdbc:mysql://localhost:3306/db1216"/>
                        <property name="username" value="root"/>
                        <property name="password" value="root"/>
                    </dataSource>
                </environment>
            </environments>
            <mappers>
                <!-- 设置映射文件路径-->
                <mapper resource="mapper/EmployeeMapper.xml"/>
            </mappers>
        </configuration>
        
    • 新建接口【Mapper(Dao)】

      import com.atguigu.ssm.pojo.Employee;
      
      /**
       * @author Chunsheng Zhang 尚硅谷
       * @create 2022/3/2 10:34
       */
      public interface EmployeeMapper {
      
      
          /**
           * 通过id获取员工信息
           */
          public Employee selectEmpById(int id);
      
      }
      
    • 编写映射文件【为Mapper编写SQL】

      • 位置:resources/mapper目录下

      • 映射文件三个一致

        • 映射文件名与接口名一致
        • 映射文件中namespace与接口的全类名一致
        • 映射文件中sqlId与接口中方法名一致
      • 示例代码

        <?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.atguigu.ssm.mapper.EmployeeMapper">
        
            <select id="selectEmpById" resultType="com.atguigu.ssm.pojo.Employee">
                SELECT
                    id,
                    last_name lastName,
                    email,
                    salary
                FROM
                    tbl_employee
                WHERE id = #{id}
            </select>
        </mapper>
        
    • 测试【SqlSession】

      • 先获取SqlSessionFactory

      • 再通过SqlSessionFactory获取SqlSession

      • 通过SqlSession获取代理对象【实现类】

      • 测试

      • 示例代码

        import com.atguigu.ssm.mapper.EmployeeMapper;
        import com.atguigu.ssm.pojo.Employee;
        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.IOException;
        import java.io.InputStream;
        
        /**
         * @author Chunsheng Zhang 尚硅谷
         * @create 2022/3/2 10:45
         */
        public class TestMybatisHW {
        
        
            @Test
            public void testHw() throws IOException {
                String resource = "mybatis-config.xml";
                InputStream inputStream = Resources.getResourceAsStream(resource);
                SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
                //再通过SqlSessionFactory获取SqlSession
                SqlSession sqlSession = sqlSessionFactory.openSession();
                //通过SqlSession获取**代理对象【实现类】**
                EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
                System.out.println("mapper.getClass().getName() = " + mapper.getClass().getName());
                Employee employee = mapper.selectEmpById(1);
                System.out.println("employee = " + employee);
            }
        
        }
        

3.2 添加Log4j支持【日志框架】

  • 导入jar包

    <!--log4j-->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    
  • 编写配置文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!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>
    

第四章 Mybatis核心配置文件

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

  • 常用标签

    • 根标签:configuration,所有的子标签均需要书写在根标签内部

    • 子标签

      • properties

        • 作用:
          1. 定义property属性值
          2. 引入外部属性文件
      • settings:这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。

        • mapUnderscoreToCamelCase:是否开启驼峰命名自动映射,默认值:false
          • 如开启,会将表中字段a_bc与类中属性aBc自动映射
      • typeAliases:为JavaBean【POJO】定义别名

        1. 逐个定义别名:typeAlias
        2. 统一定义别名,指定JavaBean的包名:package
        • Mybatis自定义别名列表

          别名 全类名
          string java.lang.String
          _int int
          int【integer】 Integer
          list List
          map Map
          _double double
      • environments:设置数据库连接环境

        • 设置事务管理器:transactionManager
        • 设置连接数据库数据源:dataSource
      • mappers:设置映射文件路径

        • 基于类路径设置映射文件路径:<mapper resource="mapper/EmployeeMapper.xml"/>
  • 示例代码

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    
    <configuration>
    
    <!--    <properties >-->
    <!--        <property name="driver" value="com.mysql.jdbc.Driver"/>-->
    <!--    </properties>-->
    
        <properties resource="db.properties"></properties>
    
        <settings>
            <setting name="mapUnderscoreToCamelCase" value="true"/>
        </settings>
    
        <typeAliases>
    <!--        <typeAlias type="com.atguigu.ssm.pojo.Employee" alias="employee"></typeAlias>-->
            <package name="com.atguigu.ssm.pojo"/>
        </typeAliases>
    
    
        <environments default="development">
            <!--        设置连接数据库环境-->
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="${db.driver}"/>
                    <property name="url" value="${db.url}"/>
                    <property name="username" value="${db.username}"/>
                    <property name="password" value="${db.password}"/>
                </dataSource>
            </environment>
        </environments>
        <mappers>
            <!-- 设置映射文件路径-->
            <mapper resource="mapper/EmployeeMapper.xml"/>
    <!--        <package name="mapper"/>-->
        </mappers>
    </configuration>
    

第五章 Mybatis映射文件

5.1 映射文件概述

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

5.2 映射文件中常用标签

  • 根标签:mapper

    • namespace:与接口全类名一致
  • 子标签

    • select:定义查询SQL语句
    • insert:定义增加SQL语句
    • delete:定义删除SQL语句
    • update:定义修改SQL语句
    • resultMap:设置SQL语句结果集类型【与resultType作用一致,resultType解决不了时,使用resultMap(多表连接查询时,使用resultMap)】
    • sql:定义可重用SQL语句块
    • cache:该命名空间的缓存配置。
    • cache-ref:引用其它命名空间的缓存配置。
  • 标签中属性

    • id:SQL语句唯一标识
    • resultType:设置查询语句结果集类型。注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。 resultType 和 resultMap 之间只能同时使用一个。

5.3 在程序中获取数据库自增值

<insert id="insertEmp" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO
        tbl_employee(last_name,email,salary)
    VALUES
        (#{lastName},#{email},#{salary})
</insert>

day02_Mybatis总结

  • 注意事项
    • 映射文件中标签无顺序要求
    • 核心配置文件中的标签有顺序要求【具体顺序,参考官网文档】

day03

5.4 获取数据库受影响行数

  • 直接在方法中设置返回值类型为:int即可【支持boolean】

  • 示例代码

    /**
     * 添加员工信息
     */
    public int insertEmp(Employee employee);
    public boolean insertEmp(Employee employee);
    

第六章 Mybatis中参数传递问题

6.1 单个普通类型参数

  • 可直接入参使用即可,无考虑参数名及参数类型等问题

6.2 多个普通类型参数

  • mybatis底层封装Map结构,参数的key是arg0、arg1、...【或param1、param2、....】

6.3 命名参数

  • mybatis底层封装Map结构,参数的key是@Param注解命名的【同时支持:param1,param2】

6.4 POJO【JavaBean】

  • mybatis支持POJO直接入参的,参数的key是POJO中属性名
  • mybatis获取POJO中参数,是通过getXXX()方法获取的

6.5 Map

  • mybatis支持Map入参,参数的key是Map的key

6.6 Collection|List|Array

  • mybatis也支持Collection、List、Array入参,Collection对应的key是collection,Array对应的key是array. 如果确定是List集合,key还可以是list。

6.7 源码解析命名参数底层原理

  • MapperMethod中execute()入口

  • MapperMethod中86行【导入源码后】,进入源码

  • ParamNameResolver中getNamedParams(),命名参数底层原理

    else {
      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
        if (!names.containsValue(genericParamName)) {
          param.put(genericParamName, args[entry.getKey()]);
        }
        i++;
      }
    
    • 总结
      • Mybatis底层封装Map,本质是ParamMap 继承 HashMap

第七章 Mybatis中#与$区别【面试题】

  • JDBC关键对象【DriverManager、Connection、PreparedStatement、ResultSet】
    • Statement:底层传递SQL参数时,使用拼接SQL方式,存在SQL注入安全隐患
    • PreparedStatement:底层传递SQL参数时,使用?【占位符】方式,相对安全

7.1 #与$概述

  • :Mybatis中#传递参数底层使用PreparedStatement对象,使用占位符方式,相对安全

  • $:Mybatis中#传递参数底层使用Statement对象,字符串拼接方式,相对不安全

7.2 $使用场景

完整查询SQL:

select col,col2... from tbl1 where ? group by ? order by ? limit ?,?

  • 示例代码

    /**
     * 测试动态查询表中数据【表名动态化】
     */
    public List<Employee> selectEmpByOpr(@Param("tblName") String tblName);
    
    <select id="selectEmpByOpr" resultType="employee">
        SELECT
            id,
            last_name,
            email,
            salary
        FROM
            ${tblName}
    </select>
    

第八章 Mybatis常见四种查询结果

8.1 查询单行数据返回单个对象

/**
 * 通过id获取员工信息
 */
public Employee selectEmpById(int id);
<select id="selectEmpByIdAndName" resultType="employee">
    SELECT
        id,
        last_name,
        email,
        salary
    FROM
        tbl_employee
    WHERE
        id = #{param1}
    AND
        last_name=#{param2}
</select>

8.2 查询多行数据返回对象的集合

/** *  获取所有员工信息 */public List<Employee> selectAllEmps();
<!--    定义SQL【获取所有员工信息】--><select id="selectAllEmps" resultType="employee">    SELECT    id,    last_name,    email,    salary    FROM    tbl_employee</select>

8.3 查询单行数据返回Map集合

  • 将数据库表中的字段,作为key;数据作为value;所以建议Map的key使用String类型

    /** * 测试查询单行数据,返回Map */public Map<String,Employee> selectEmpReturnMap(int id);
    
    <select id="selectEmpReturnMap" resultType="map">
        SELECT
            id,
            last_name,
            email,
            salary
        FROM
            tbl_employee
        WHERE
            id = #{id}
    </select>
    

8.4 查询多行数据返回Map集合

  • Map的key是对象的Id,Map的value是对象本身。

  • 注意:必须使用@MapKey注解,设置对象的Id,如未设置会报如下错误:

    org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 8
    
  • 示例代码

    /**
     * 测试查询多行数据,返回Map
     * key:id
     * value:Employee
     */
    @MapKey("id")
    public Map<Integer,Employee> selectAllEmpReturnMap();
    
    <select id="selectAllEmpReturnMap" resultType="map">
        SELECT
            id,
            last_name,
            email,
            salary
        FROM
            tbl_employee
    </select>
    

第九章 Mybatis中自动映射及自定义映射【重点】

9.1 自动映射【resultType】与自定义映射【resultMap】概述

  • 自动映射:将结果集中的字段与对象中的属性【Map中的key】自动映射
  • 自定义映射:将结果集中的字段与对象中的属性【Map中的key】自定义映射
  • 总结:
    • resultType解决不了时,使用resultMap
    • resultMap适用场景:多表连接查询时较多

9.2 使用自定义映射

  • 级联映射

    /**
     * 通过id获取员工信息及员工所属部门信息
     */
    public Employee selectEmpAndDeptByEmpId(int id);
    
    <!--    通过员工id获取员工信息及员工所属部门信息-->
        <resultMap id="empAndDeptResultMap" type="employee">
            <!-- 自定义映射关系【主键】-->
            <id property="id" column="id"></id>
            <!-- 自定义映射关系【非主键】-->
            <result property="lastName" column="last_name"></result>
            <result property="email" column="email"></result>
            <result property="salary" column="salary"></result>
            <!--【级联映射】 自定义部门关联关系-->
            <result property="dept.deptId" column="dept_id"></result>
            <result property="dept.deptName" column="dept_name"></result>
        </resultMap>
    
        <select id="selectEmpAndDeptByEmpId" resultMap="empAndDeptResultMap">
            SELECT
                e.id,e.`last_name`,e.`email`,e.`salary` ,
                d.`dept_id`,d.`dept_name`
            FROM
                tbl_employee e,tbl_dept d
            WHERE
                e.`dept_id`=d.`dept_id`
            AND
               e.`id` = #{id}
        </select>
    
  • association【一对一或多对一】

    /**
     * 通过id获取员工信息及员工所属部门信息【association】
     */
    public Employee selectEmpAndDeptByEmpIdAssociation(int id);
    
    <resultMap id="empAndDeptResultMapAssociation" type="employee">
            <!-- 自定义映射关系【主键】-->
            <id property="id" column="id"></id>
            <!-- 自定义映射关系【非主键】-->
            <result property="lastName" column="last_name"></result>
            <result property="email" column="email"></result>
            <result property="salary" column="salary"></result>
    <!--        association-->
            <association property="dept" javaType="com.atguigu.ssm.pojo.Dept">
                <id property="deptId" column="dept_id"></id>
                <result property="deptName" column="dept_name"></result>
            </association>
        </resultMap>
    
        <select id="selectEmpAndDeptByEmpIdAssociation" resultMap="empAndDeptResultMapAssociation">
            SELECT
                e.id,e.`last_name`,e.`email`,e.`salary` ,
                d.`dept_id`,d.`dept_name`
            FROM
                tbl_employee e,tbl_dept d
            WHERE
                e.`dept_id`=d.`dept_id`
            AND
               e.`id` = #{id}
        </select>
    

9.3 ResultMap标签

  • 属性
    • id:设置ResultMap唯一标识
    • type:设置ResultMap类型
  • 子标签
    • id:定义主键映射关系【对象中的属性与表中字段的映射关系】
    • result:定义非主键映射关系
    • association:定义一对一【或多对一】的映射关系
    • collection:定义一对多的映射关系
      • 属性
        • property:定义映射属性
        • ofType:定义映射属性类型【全类名】,如association使用javaType
        • select:设置SQL语句Id的全路径【分步查询】
        • column:设置SQL语句参数【分步查询】
        • fetchType:局部设置延迟加载是否开启
          • lazy:开启延迟加载
          • eager:关闭延迟加载

day03_总结

  1. Mybatis中参数传递问题
    • 看源码:命名参数底层源码
  2. 与$区别【面试题】

  3. 自定义映射【级联映射&association映射】

day04

9.4 association自定义映射分步查询及延迟加载【一对一】

  • 分步查询

    • 为什么需要分步查询【分步查询优势】
      • 分步查询时一般单表查询,比较多表连接查询,效率高。
  • 延迟加载【懒加载】

    • 概述:需要数据时加载,不需要时不加载

    • 语法

      • 全局配置

        lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。默认值:false

      • 局部配置

        fetchType="eager":关闭延迟加载

        fetchType="lazy":开启延迟加载

        <association        property="dept"        select="com.atguigu.ssm.mapper.DeptMapper.selectDeptById"        column="dept_id"        fetchType="eager"></association>
        
  • 示例代码

    • 员工信息
    /**
     * 通过员工id获取员工信息及员工所属部门信息【association分步查询】
     *      *      1. 通过员工id获取员工信息
     *      *      2. 通过员工id,获取部门id,再通过部门id获取部门信息
     *  为分步查询做准备
     */
    public Employee selectEmpAndDeptByEmpIdAssociationStep(int id);
    
    <!--    association分步查询-->
        <resultMap id="empAndDeptAssociationStep" type="employee">
            <!-- 自定义映射关系【主键】-->
            <id property="id" column="id"></id>
            <!-- 自定义映射关系【非主键】-->
            <result property="lastName" column="last_name"></result>
            <result property="email" column="email"></result>
            <result property="salary" column="salary"></result>
    <!--        关联部门-->
            <association
                    property="dept"
                    select="com.atguigu.ssm.mapper.DeptMapper.selectDeptById"
                    column="dept_id"
                    fetchType="eager">
    
            </association>
        </resultMap>
        <select id="selectEmpAndDeptByEmpIdAssociationStep" resultMap="empAndDeptAssociationStep">
            SELECT
                id,
                last_name,
                email,
                salary,
                dept_id
            FROM
                tbl_employee
            WHERE
                id = #{id}
        </select>
    
    • 部门信息
    /**
     * 通过部门id获取部门信息
     * 为分步查询做准备
     */
    public Dept selectDeptById(int deptId);
    
    <select id="selectDeptById" resultType="dept">
        select
            dept_id,
            dept_name
        from
            tbl_dept
        where
            dept_id = #{deptId}
    </select>
    

9.5 Collection自定义映射分步查询及延迟加载【一对多】

  • 部门信息
/**
 * 分步查询【通过部门id获取部门信息,及部门中所有员工信息】
 *      1. 通过部门id获取部门信息
 *      2. 通过部门id获取员工信息
 */
Dept selectDeptAndEmpByDeptIdStep(int deptId);
<resultMap id="deptAndEmpStep" type="dept">
    <id property="deptId" column="dept_id"></id>
    <result property="deptName" column="dept_name"></result>
    <collection property="employees"
                select="com.atguigu.ssm.mapper.EmployeeMapper.selectEmpByDeptId"
                column="dept_id"
                fetchType="lazy">
    </collection>
</resultMap>
<select id="selectDeptAndEmpByDeptIdStep" resultMap="deptAndEmpStep">
    select
        dept_id,
        dept_name
    from
        tbl_dept
    where
        dept_id = #{deptId}
</select>
  • 员工信息
/**
 * 通过部门id获取员工信息
 */
List<Employee> selectEmpByDeptId(int deptId);
<select id="selectEmpByDeptId" resultType="employee">
    SELECT
        id,
        last_name,
        email,
        salary,
        dept_id
    FROM
        tbl_employee
    WHERE
        dept_id = #{deptId}
</select>

第十章 Mybatis中动态SQL【重点】

Thymeleaf:动态渲染数据【HTML】

动态SQL:指的是SQL可动态变化

10.1 if与where

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

  • where标签:用于解决SQL语句中where关键字以及条件前面的第一个and或者or的问题

  • trim标签:添加或删除前后指定字符

    • prefix:添加前缀字符
    • prefixOverrides:删除前缀字符
    • suffix:添加后缀字符
    • suffixOverrides:删除后缀字符
  • set标签:用于解决set关键字,及多出一个逗号【,】问题

  • choose标签:用于单条件分支结构【类似流程控制中if-else】

  • foreach标签:用于循环【类似流程控制中循环结构】

  • sql片段:用于提取可重复使用sql片段

10.2 示例代码总结

<?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.atguigu.ssm.mapper.EmployeeMapper">

    <sql id="col_employee">
        id,
        last_name,
        email,
        salary,
        dept_id
    </sql>
    
    <sql id="select_employee">
        SELECT
            id,
            last_name,
            email,
            salary,
            dept_id
        FROM
            tbl_employee
    </sql>
    
    <select id="selectEmpByEmp" resultType="employee">
        <include refid="select_employee"></include>
            <!-- SSS -->
--             SFDSF
        <where>
             <if test="id != null">
<!--           id = #{id} -->
                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>

    <select id="selectEmpByEmpTrim" 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}  AND
            </if>
        </trim>
    </select>

    <update id="updateEmpByEmp">
        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>

    <select id="selectEmpByEmpChoose" resultType="employee">
        SELECT
            <include refid="col_employee"></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>


    <select id="selectEmpsByIds" resultType="employee">
        SELECT
            id,
            last_name,
            email,
            salary,
            dept_id
        FROM
            tbl_employee
        WHERE
            id in (
                <foreach collection="ids" item="id" separator=",">
                    #{id}
                </foreach>
            )
    </select>

    <insert id="insertBatchEmp">
        INSERT INTO
            tbl_employee(last_name,email,salary)
        VALUES
            <foreach collection="emps" item="emp" separator=",">
                (#{emp.lastName},#{emp.email},#{emp.salary})
            </foreach>
    </insert>


</mapper>

第十一章

11.1 缓存概念

  • 生活中缓存
    • 内容:缓存音频视频等
    • 优势:节约数据流量,提高性能
  • Mybatis程序中缓存
    • 内容:缓存数据【数据库】
    • 优势:提高查询效率,减低服务器压力

11.2 Mybatis中一级缓存

  • 一级缓存【本地缓存】,默认开启,不能关闭。
  • 一级缓存作用域:SqlSession

11.3 一级缓存工作原理

  • 第一次获取数据时,先从数据库中查询指定数据。将数据缓存到一级缓存【Map结构,key:hashCode+查询的SqlId+编写的sql查询语句+参数】
  • 以后在同一个SqlSession中,获取相同数据时,会先从一级缓存中获取数据,如一级缓存中没有指定数据,再从数据库中获取【在缓存到一级缓存】

11.4 一级缓存五种失效情况

  1. 不同的SqlSession对应不同的一级缓存

  2. 同一个SqlSession但是查询条件不同

  3. 同一个SqlSession两次查询期间执行了任何一次增删改操作

  4. 同一个SqlSession两次查询期间手动清空了缓存

  • sqlSession.clearCache()
  1. 同一个SqlSession两次查询期间提交了事务

day05

11.6 Mybatis中二级缓存

  • 二级缓存(second level cache),全局作用域缓存【SqlSessionFactory】
  • 二级缓存默认不开启,需要手动开启并配置

11.7 使用Mybatis二级缓存步骤

① 全局配置文件中开启二级缓存

② 需要使用二级缓存的映射文件处使用cache配置缓存

③ 注意:POJO需要实现Serializable接口

④ 关闭sqlSession或提交sqlSession时,将数据缓存到二级缓存

11.8 Mybatis二级缓存工作原理

  • 第一次获取数据时,从数据库中查询指定数据。并先将数据缓存至一级缓存,再关闭或提交SqlSession时,将数据缓存至二级缓存
  • 以后在获取数据时,先从一级缓存中获取数据,如获取不到数据;再从二级缓存中获取数据【如未获取到数据】,则从数据库中获取数据【并重复上述操作】

11.9 Mybatis二级缓存相关属性

  • eviction:缓存清除【回收】策略:

    • LRU – 最近最少使用的:移除最长时间不被使用的对象。
    • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
  • flushInterval:刷新间隔,单位毫秒

    • 默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
  • size:引用数目,正整数

    • 代表缓存最多可以存储多少个对象,太大容易导致内存溢出
  • readOnly:只读,true/false

11.10 Mybatis支持第三方缓存【EhCache】

  • 使用步骤

    • 导入jar包

      <!-- mybatis-ehcache -->
      <dependency>
          <groupId>org.mybatis.caches</groupId>
          <artifactId>mybatis-ehcache</artifactId>
          <version>1.0.3</version>
      </dependency>
      
      <!-- slf4j-log4j12 -->
      <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-log4j12</artifactId>
          <version>1.6.2</version>
          <scope>test</scope>
      </dependency>
      
    • 编写EhCache配置文件

      • 位置:resources

      • 名称:ehcache.xml

      • 示例代码

        <?xml version="1.0" encoding="UTF-8"?>
        <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
            <!-- 磁盘保存路径 -->
            <diskStore path="E:\mybatis\ehcache" />
        
            <defaultCache
                    maxElementsInMemory="512"
                    maxElementsOnDisk="10000000"
                    eternal="false"
                    overflowToDisk="true"
                    timeToIdleSeconds="120"
                    timeToLiveSeconds="120"
                    diskExpiryThreadIntervalSeconds="120"
                    memoryStoreEvictionPolicy="LRU">
            </defaultCache>
        </ehcache>
        
                <!--
                属性说明:
                l diskStore:指定数据在磁盘中的存储位置。
                l defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略
        
                以下属性是必须的:
                l maxElementsInMemory - 在内存中缓存的element的最大数目
                l maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大
                l eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断
                l overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
        
                以下属性是可选的:
                l timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大
                l timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
                 diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区.
                l diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。
                l diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作
                l memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)
                 -->
        
    • 开启第三方缓存【映射文件】

      <cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
      
  • 注意:第三方缓存使用是建立在二级缓存的基础之上的。

第十二章 Mybatis逆向工程

12.1 逆向工程概述

  • 正向工程:通过Java工程【Mapper&POJO】,影响数据库中数据

  • 逆向工程:通过数据库,影响Java工程【Mapper&POJO】

  • 逆向工程简介

    • MyBatis Generator: 简称MBG,是一个专门为MyBatis框架使用者定制的代码生成器,可以快速的根据表生成对应的映射文件,接口,以及bean类。
    • 支持基本的增删改查,以及QBC风格的条件查询。
  • 官方文档地址

    http://www.mybatis.org/generator/

12.2 逆向工程使用步骤

  • 导入jar包

    <dependencies>
    
        <!--导入MyBatis的jar包-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>
        <!--        Mysql驱动包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.37</version>
        </dependency>
    
        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    
        <!--log4j-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    
        <!-- mybatis-generator-core -->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.6</version>
        </dependency>
    </dependencies>
    
  • 编写配置文件

    • 位置:resources

    • 名称:mbg.xml

    • 示例代码

      <!DOCTYPE generatorConfiguration PUBLIC
              "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
              "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
      <generatorConfiguration>
          <!--
             id属性:设置一个唯一标识
             targetRuntime属性值说明:
               MyBatis3Simple:基本的增删改查
               MyBatis3:带条件查询的增删改查【QBC风格查询】
          -->
          <context id="simple" targetRuntime="MyBatis3Simple">
              <!--设置连接数据库的相关信息-->
              <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                              connectionURL="jdbc:mysql://localhost:3306/db1216"
                              userId="root"
                              password="root"/>
      
              <!--设置JavaBean的生成策略-->
              <javaModelGenerator targetPackage="com.atguigu.mybatis.mbg.pojo" targetProject="src/main/java"/>
      
              <!--设置SQL映射文件的生成策略-->
              <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources"/>
      
              <!--设置Mapper接口的生成策略-->
              <javaClientGenerator type="XMLMAPPER" targetPackage="com.atguigu.mybatis.mbg.mapper" targetProject="src/main/java"/>
      
              <!--逆向分析的表-->
              <table tableName="tbl_employee" domainObjectName="Employee"/>
              <table tableName="tbl_dept" domainObjectName="Department"/>
          </context>
      
      
      </generatorConfiguration>
      
  • 使用代码生成器,生成相关代码

    @Test
    public void testMBG() throws IOException, XMLParserException, InvalidConfigurationException, SQLException, InterruptedException {
        List<String> warnings = new ArrayList<String>();
        boolean overwrite = true;
        File configFile = new File("src/main/resources/mbg.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);
    }
    

12.3 逆向工程之QBC风格

  • mbg.xml中设置

    <context id="simple" targetRuntime="MyBatis3">
    
  • 使用条件对象【XXXExample】

     @Test
        public void testCache2(){
            SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
            SqlSession sqlSession = sqlSessionFactory.openSession();
            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
    
            //测试普通MBG
    //        List<Employee> employees = mapper.selectAll();
    //        for (Employee employee : employees) {
    //            System.out.println("employee = " + employee);
    //        }
    
            //测试QBC风格MBG
            EmployeeExample ee = new EmployeeExample();
            //为条件对象【ee】设置条件
            EmployeeExample.Criteria criteria = ee.createCriteria();
            criteria.andIdBetween(1,10);
            criteria.andSalaryGreaterThanOrEqualTo(100000.0);
            criteria.andLastNameLike("%i%");
    
            List<Employee> employees = mapper.selectByExample(ee);
            for (Employee employee : employees) {
                System.out.println("employee = " + employee);
            }
    
    
        }
    

第十三章 分页插件【PageHelper】

13.1 分页基本概念

  • 为什么需要分页?

    • 提高用户体验度
    • 降低服务器压力
  • 手动搭建分页【Page工具类】

    • pageNum【当前页码】
    • pages【总页码=总数据条数/每页显示数量】
    • total【总数据条数】
    • pageSize【每页显示数量】
    • List【当前页显示数据集合】

13.2 使用Mybatis中分页插件【PageHelper】

  • PageHelper是MyBatis中非常方便的第三方分页插件

  • PageHelper使用步骤

    • 导入jar包

      <!-- pagehelper -->
      <dependency>
          <groupId>com.github.pagehelper</groupId>
          <artifactId>pagehelper</artifactId>
          <version>5.0.0</version>
      </dependency>
      
    • 在MyBatis全局配置文件中配置分页插件

      • 书写位置:核心配置文件【mybatis-config.xml】中的环境上面即可
      <plugins>
          <!--配置PageHelper分页插件-->
          <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
      </plugins>
      
    • 使用PageHelper提供的方法进行分页【在查询之前开启分页

      //开启分页插件功能
      PageHelper.startPage(pageNum, pageSize);
      
    • 可以使用更强大的PageInfo封装返回结果

      @Test
      public void testPageInfo(){
      
          SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
          SqlSession sqlSession = sqlSessionFactory.openSession();
          EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
      
          //开启分页
          PageHelper.startPage(9, 3);
      
          //测试QBC风格MBG
          EmployeeExample ee = new EmployeeExample();
          List<Employee> employees = mapper.selectByExample(ee);
          for (Employee employee : employees) {
              System.out.println("employee = " + employee);
          }
      
          //查询之后,将结果封装PageInfo
          PageInfo<Employee> pageInfo = new PageInfo<>(employees,5);
          System.out.println("=====================================");
      
          System.out.println(pageInfo.getPageNum()+"/"+pageInfo.getPages());
          System.out.println("总条数:"+pageInfo.getTotal());
          System.out.println("每页显示条数:"+pageInfo.getPageSize());
          for (Employee employee : pageInfo.getList()) {
              System.out.println("employee = " + employee);
          }
      
          System.out.println("页码信息:");
          int[] navigatepageNums = pageInfo.getNavigatepageNums();
          for (int navigatepageNum : navigatepageNums) {
              System.out.print(navigatepageNum+"  ");
          }
      
          System.out.println("是否有上一页:"+pageInfo.isHasPreviousPage());
          System.out.println("上一页是:"+pageInfo.getPrePage());
          System.out.println("是否有下一页:"+pageInfo.isHasNextPage());
          System.out.println("下一页是:"+pageInfo.getNextPage());
          System.out.println("是否是第一页:"+pageInfo.isIsFirstPage());
          System.out.println("是否是最后一页:"+pageInfo.isIsLastPage());
          System.out.println("导航页的第一个页码是:"+pageInfo.getNavigateFirstPage());
          System.out.println("导航页的最后一个页码是:"+pageInfo.getNavigateLastPage());
          System.out.println("导航页的总页码是:"+pageInfo.getNavigatePages());
      
      
      }
      

13.3 PageHelper底层实现原理

  • //开始下标【index】=(pageNum-1)*pageSize
    PageHelper.startPage(2,3);
    
  • -- 分页底层执行两条SQl
    -- 1. 查询数据库数量【total(总数据条数)】
    SELECT count(0) FROM tbl_employee
    -- 2. 查询当前页显示数据集合【List<T>(当前页显示数据集合)】
    select id, last_name, email, salary, dept_id from tbl_employee LIMIT 3,3
    
posted @   jiejie0830  阅读(97)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示