尚硅谷-Mybatis笔记

一.Mybatis下载

下载地址:MyBatis · GitHub

1.打开下载地址 

2.点击mybatis-3进去后直接往下拉到下图界面,选中Download Latest

3.选中你想要的版本开始下载

二.MyBatis的搭建

1.创建Maven工程并引入依赖

  <?xml version="1.0" encoding="UTF-8"?>
  <project xmlns="http://maven.apache.org/POM/4.0.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
  ​
      <groupId>com.hjj.mybatis</groupId>
      <artifactId>mybatis_helloworld</artifactId>
      <version>1.0-SNAPSHOT</version>
      
      <properties>
          <maven.compiler.source>8</maven.compiler.source>
          <maven.compiler.target>8</maven.compiler.target>
      </properties>
      <packaging>jar</packaging>
      <dependencies>
          <!-- Mybatis核心 -->
          <dependency>
              <groupId>org.mybatis</groupId>
              <artifactId>mybatis</artifactId>
              <version>3.5.13</version>
          </dependency>
      
          <!-- junit测试 -->
          <dependency>
              <groupId>junit</groupId>
              <artifactId>junit</artifactId>
              <version>4.12</version>
              <scope>test</scope>
          </dependency>
      
          <!-- MySQL驱动 -->
          <dependency>
              <groupId>mysql</groupId>
              <artifactId>mysql-connector-java</artifactId>
              <version>8.0.31</version>
          </dependency>
      </dependencies>
  </project>

2.创建MyBatis核心配置文件

习惯上命名为mybatis-config.xml

核心配置文件主要用于配置连接数据库的环境以及MyBatis的全局配置信息

核心配置文件存放的位置是src/main/resources目录下

注意事项:

1、驱动类driver-class-name

MySQL 5版本使用jdbc5驱动,驱动类使用:com.mysql.jdbc.Driver

MySQL 8版本使用jdbc8驱动,驱动类使用:com.mysql.cj.jdbc.Driver2、连接地址url

MySQL 5版本的url:

j>dbc:mysql://localhost:3306/ssm

MySQL 8版本的url:

jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC

  
  <?xml version="1.0" encoding="UTF-8" ?>
  <!--Mybatis核心配置文件主要用于配置连接数据库的环境以及MyBatis的全局配置信息-->
  <!DOCTYPE configuration
          PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
          "https://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:3307/ssm?serverTimezone=UTC"/>
                  <property name="username" value="root"/>
                  <property name="password" value=""/>
              </dataSource>
          </environment>
      </environments>
  ​
  <!--    引入mybatis映射文件-->
      <mappers>
          <mapper resource="mappers/UserMapper.xml"/>
      </mappers>
  </configuration>
  ​

3.创建Mapper接口

int insertUser()1.mapper接口和映射文件的namespace一致2.mapper接口中方法名要与映射文件中的sql的id保持一致

  
  public interface UserMapper {
  ​
      int insertUser();
  }

4.创建MyBatis映射文件

1、映射文件的命名规则:

一个映射文件对应一个实体类,对应一张表的操作,表所对应的实体类的类名+Mapper.xml

例如:表t_user,映射的实体类为User,所对应的映射文件为UserMapper.xml

MyBatis映射文件用于编写SQL,访问以及操作表中的数据

MyBatis映射文件存放的位置是src/main/resources/mappers目录下

2、 MyBatis中可以面向接口操作数据,要保证两个一致:

a>mapper接口的全类名和映射文件的命名空间(namespace)保持一致

b>mapper接口中方法的方法名和映射文件中编写SQL的标签的id属性保持一致

  
  <?xml version="1.0" encoding="UTF-8" ?>
  ​
  <!DOCTYPE mapper
          PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
          "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
  <mapper namespace="com.hjj.mybatis.mapper.UserMapper">
  <!--    int insertUser()
  1.mapper接口和映射文件的namespace一致
  2.mapper接口中方法名要与映射文件中的sql的id保持一致
  -->
      <insert id="insertUser">
          insert into t_user values(1,'admin','123456',23,'男','[email protected]')
      </insert>
  </mapper>

5.测试功能

  
  package com.hjj.mybatis.test;
  ​
  //        SqlSession:代表Java程序和数据库之间的会话。(HttpSession是Java程序和浏览器之间的会话)
  //
  //        SqlSessionFactory:是“生产”SqlSession的“工厂”。
  //
  //        工厂模式:如果创建某一个对象,使用的过程基本固定,那么我们就可以把创建这个对象的
  //
  //        相关代码封装到一个“工厂类”中,以后都使用这个工厂类来“生产”我们需要的对象。
  import com.hjj.mybatis.mapper.UserMapper;
  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 javax.annotation.Resource;
  import java.io.IOException;
  import java.io.InputStream;
  ​
  /**
   * @author:嘉佳 Date:2023/3/18 14:56
   **/
  public class MyBatisTest {
  ​
      @Test
      public void testInsert() throws IOException {
  //        获取核心配置文件的输入流
          InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
  //        获取SqlSessionFactoryBuilder对象
          SqlSessionFactoryBuilder sqlSessionFactoryBuilder=new SqlSessionFactoryBuilder();
  //        获取SqlSessionFactory对象
          SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
  //        获取sql的会话对象SqlSession-》Mybatis提供的操作数据库的对象
          SqlSession sqlSession = sqlSessionFactory.openSession();
  //        通过代理模式获取UserMapper的代理实现类对象
          UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  //        调用mapper接口中的方法,实现添加用户信息的功能
          //调用UserMapper接口中的方法,就可以根据UserMapper的全类名匹配元素文件,通过调用的方法名匹配
          //映射文件中的SQL标签,并执行标签中的SQL语句
          int result=mapper.insertUser();
          System.out.println("结果"+result);
  //        提交事务
          sqlSession.commit();
          sqlSession.close();
  ​
      }
  }

6.加入log4j功能

1.在pom.xml中加入依赖

  
    <!-- log4j日志 -->
      <dependency>
          <groupId>log4j</groupId>
          <artifactId>log4j</artifactId>
          <version>1.2.17</version>
      </dependency>

2.加入log4j的配置文件

log4j的配置文件名为log4j.xml,存放的位置是src/main/resources目录下

  
  <?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>

日志的级别

FATAL(致命)>ERROR(错误)>WARN(警告)>INFO(信息)>DEBUG(调试)

从左到右打印的内容越来越详细

三.Mybatis获取参数值

MyBatis获取参数值的两种方式:${}和#{}

${}的本质就是字符串拼接,#{}的本质就是占位符赋值${}使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;但是#{}使用占位符赋值的方式()拼接sql,此时为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号并且可以避免sql注入

若mapper接口的参数为:

1.单个字面量类型的参数

若mapper接口中的方法参数为单个的字面量类型,此时可以使用${}和#{}以任意的名称获取参数的值,注意前者需要手动加单引号

  
   <select id="getUserByUsername" resultType="User">
  <!--        select * from t_user where username = #{username}-->
          select * from t_user where username = '${username}'
      </select>

2.多个字面量类型的参数

若mapper接口中的方法参数为多个时,此时MyBatis会自动将这些参数放在一个map集合中,以arg0,arg1...为键,以参数为值;以param1,param2...为键,以参数为值;因此只需要通过${}和#{}访问map集合的键就可以获取相对应的值

3.map集合类型的参数

mapper接口中的方法需要的参数为多个时,此时可以手动创建map集合,将这些数据放在map中只需要通过${}和#{}访问map集合的键就可以获取相对应的值

4.实体类类型的参数

若mapper接口中的方法参数为实体类对象时, 此时可以使用${}和#{},通过访问实体类对象中的属性名(只跟get、set方法有关系)获取属性值

5.使用@Param标识参数

可以通过@Param注解标识mapper接口中的方法参数,此时MyBatis会将这些参数放在map集合中,以@Param注解的value属性值为键,以参数为值;只需要通过${}和#{}访问map集合的键就可以获取相对应的值

四.MyBatis查询功能

1.查询一个实体类对象

SelectMapper.java:

  
       * 根据id查找用户信息
       * @param id
       * @return
       */
      User getUserById(@Param("id") Integer id);

SelectMapper.xml

  
  <!--    User getUserById(@Param("id") Integer id);-->
      <select id="getUserById" resultType="User">
          select * from t_user where id= #{id}
      </select>

2.查询一个list集合

SelectMapper.java:

  
      /**
       * 查询所有用户信息
       * @return
       */
      List<User> getAllUser();

SelectMapper.xml:

  
  <!--    List<User> getAllUser();-->
      <select id="getAllUser" resultType="User">
          select * from t_user
      </select>

当查询的数据为多条时,不能使用实体类作为返回值,否则会抛出异常TooManyResultsException(返回值与查询出的条数不一致);但是若查询的数据只有一条,可以使用实体类或集合作为返回值

3.查询单个数据

  
      /**
       * 查询用户的总记录数
       * @return
       * 在MyBatis中,对于Java中常用的类型都设置了类型别名(不区分大小写
       * 例如: java.lang.Integer-->int|integer
       * 例如: int-->_int|_integer
       * 例如: Map-->map,List-->list
       */
      int getCount();
  
  <select id="getCount" resultType="_integer">
          select count(*) from t_user
      </select>

4.查询一条数据为map集合

  
   /**
       * 根据用户id查询用户信息为map集合
       * @param id
       * @return
       */
      Map<String,Object> getUserByIdToMap(@Param("id")int id);
  
  <!--Map<String,Object> getUserByIdToMap(@Param("id")int id);-->
  <!-- 结果:(以字段名为键){password=123456, gender=男, id=1, age=23, [email protected], username=admin}-->
      <select id="getUserByIdToMap" resultType="Map">
          select * from t_user where id=#{id}
      </select>

5.查询多条数据为map集合

  
   /**
       * 查询所有用户信息为map集合
       * @return
       * 将表中的数据以map集合的方式查询,一条数据对应一个map;若有多条数据,就会产生多个map集合,此
      时可以将这些map放在一个list集合中获取
       */
      List<Map<String,Object>> getAllUserToMap();
  
  <!--    List<Map<String,Object>> getAllUserToMap();-->
      <select id="getAllUserToMap" resultType="Map">
          select * from t_user
      </select>

五.特殊SQL的执行

1.模糊查询

  
      /**
       * 通过用户名模糊查询用户信息
       * @param mohu
       * @return
       */
      List<User> getUserByLike(@Param("mohu") String mohu);
  
  <!--     List<User> getUserByLike(@Param("mohu") String mohu);-->
  <!--    '%#{}%'没有字符串拼接作用,会被解析成字符串-->
      <select id="getUserByLike" resultType="User">
  <!--        select * from t_user where username like '%${mohu}%'-->
  <!--        select * from t_user where username like concat('%',#{mohu},'%')-->
          select * from t_user where username like "%"#{mohu}"%"
      </select>

2.批量删除

  
  ​
      /**
       * 批量删除
       * @param ids
       * @return
       */
      void deleteMore(@Param("ids")String ids);
  
  <!--    void deleteMore(@Param("ids")String ids);-->
      <select id="deleteMore">
          delete from t_user where id in (${ids})
      </select>

3.动态设置表名

  
      /**
       * 动态设置表名-》查询当前用户信息
       * @param tableName
       * @return
       */
      List<User>  getUserList(@Param("tableName")String tableName);
   
  
  <!--List<User>  getUserList(@Param("tableName")String tableName);-->
      <select id="getUserList" resultType="User">
          select * from ${tableName}
      </select>

4.添加功能自增的主键

场景模拟:t_clazz(clazz_id,clazz_name)t_student(student_id,student_name,clazz_id)1、添加班级信息2、获取新添加的班级的id3、为班级分配学生,即将某学的班级id修改为新添加的班级的id

  
   /**
       * 添加用户信息并获取自增主键
       * @param user
       */
      void insertUser(User user);
  
  <!--    void insertUser(User user);*-->
  <!--    useGeneratedKeys:是否使用自增的主键-->
  <!--    keyProperty:因为增删改有统一的返回值是受影响的行数,
  因此只能将获取的自增的主键放在传输的参数user对象的某个属性中
  实际上就是添加一个数据并在id上回显添加成功的这次id-->
      <insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
          insert into t_user values(null,#{username},#{password},#{age},#{gender},#{email})
      </insert>

六.自定义映射resultMap

1.处理字段和属性之间的关系

若字段名和实体类中的属性名不一致,但是字段名符合数据库的规则(使用_),实体类中的属性名符合Java的规则(使用驼峰)此时也可通过以下两种方式处理字段名和实体类中的属性的映射关系a>可以通过为字段起别名的方式,保证和实体类中的属性名保持一致b>可以在MyBatis的核心配置文件中设置一个全局配置信息mapUnderscoreToCamelCase,可以在查询表中数据时,自动将_类型的字段名转换为驼峰

  
     <settings>
  <!--    将下划线字段名转为驼峰-->
          <setting name="mapUnderscoreToCamelCase" value="true"/>
      </settings>
      

c>通过resultMap设置自定义映射

  
   <!--
          resultMap:设置自定义映射
          属性:
          id:表示自定义映射的唯一标识
          type:查询的数据要映射的实体类的类型
          子标签:
          id:设置主键的映射关系
          result:设置普通字段的映射关系
          association:设置多对一的映射关系
          collection:设置一对多的映射关系
          属性:
          property:设置映射关系中实体类中的属性名
          column:设置映射关系中表中的字段名
      -->
  ​
      <resultMap id="empResultMap" type="Emp">
          <id column="emp_id" property="empId"></id>
          <result column="emp_name" property="empName"></result>
          <result column="age" property="age"></result>
          <result column="gender" property="gender"></result>
      </resultMap>
  <!--    Emp getEmpById(@Param("empId")Integer empId);-->
      <select id="getEmpById" resultMap="empResultMap">
          select * from t_emp where emp_id=#{empId}
      </select>

2.多对一映射处理

(1)级联方式处理多对一映射关系

  
  ​
  <!--    多对一:对象-->
      <resultMap id="empAndDeptResultMap" type="Emp">
          <id column="emp_id" property="empId"/>
          <result column="emp_name" property="empName"/>
          <result column="age" property="age"/>
          <result column="gender" property="gender"/>
          <result column="dept_id" property="dept.deptId"/>
          <result column="dept_name" property="dept.deptName"/>
      </resultMap>
  <!--    Emp getEmpAndDeptByEmpId(@Param("empId")Integer empId);-->
      <select id="getEmpAndDeptByEmpId" resultMap="empAndDeptResultMap">
          select t_emp.*,t_dept.*
              from t_emp left join t_dept
                  on t_emp.dept_id=t_dept.dept_id
                      where t_emp.emp_id=#{empId}
      </select>

(2)association方式处理多对一映射关系

  
  ​
  <!--    javaType:设置要处理的属性的类型-->
      <resultMap id="empAndDeptResultMap" type="Emp">
          <id column="emp_id" property="empId"/>
          <result column="emp_name" property="empName"/>
          <result column="age" property="age"/>
          <association property="dept" javaType="Dept">
              <id column="dept_id" property="deptId"/>
              <result column="dept_name" property="deptName"/>
          </association>
      </resultMap>

(3)分步查询处理多对一映射关系

 <resultMap id="empAndDeptByStepResultMap" type="Emp">
        <id column="emp_id" property="empId"/>
        <result column="emp_name" property="empName"/>
        <result column="age" property="age"/>
        <result column="gender" property="gender"/>
        <!--
        select:设置分步查询第二步sql的唯一标识
        column:将sql以及查询结果中的某个字段设置为分步查询的条件
	-->
        <association property="dept" select="com.hjj.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
                     column="dept_id">
            </association>
    </resultMap>

<!--    Emp getEmpAndDeptByStep(@Param("empId")Integer empId);-->
    <select id="getEmpAndDeptByStep" resultMap="empAndDeptByStepResultMap">
        select * from t_emp where emp_id=#{empId}
    </select>


分步查询的优点:可以实现延迟加载但是必须在核心配置文件中设置全局配置信息:lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。此时可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载, fetchType="lazy(延迟加载)|eager(立即加载)"

3.一对多映射处理

(1)collection

 <resultMap id="deptAndEmpResultMap" type="Dept">
        <id column="dept_id" property="deptId"/>
        <result column="dept_name" property="deptName"/>
<!--        ofType:设置集合中的类型-->
        <collection property="emps" ofType="Emp">
            <id column="emp_id" property="empId"/>
            <result column="emp_name" property="empName"/>
            <result column="age" property="age"/>
            <result column="gender" property="gender"/>
        </collection>
    </resultMap>
<!--    Dept getDeptAndEmpByDeptId(@Param("deptId")Integer deptId);-->
    <select id="getDeptAndEmpByDeptId" resultMap="deptAndEmpResultMap">
        select * from t_dept left join t_emp
            on t_dept.dept_id=t_emp.dept_id
                where t_dept.dept_id=#{deptId}
    </select>



(2)分步查询

    <resultMap id="deptAndEmpByStepResultMap" type="Dept">
        <id column="dept_id" property="deptId"/>
        <result column="dept_name" property="deptName"/>
        <collection property="emps" select="com.hjj.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo"
        column="dept_id">
        </collection>
    </resultMap>

    <select id="getDeptAndEmpByStepOne" resultMap="deptAndEmpByStepResultMap">
        select *from t_dept
            where t_dept.dept_id=#{deptId}
    </select>


七、动态SQL

Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了

解决 拼接SQL语句字符串时的痛点问题。

1.if

if标签可通过test属性的表达式进行判断,若表达式的结果为true,则标签中的内容会被拼接到SQL语句中执行;反之标签中的内容不会执行

<select id="getEmpByCondition" resultType="Emp">
        select * from t_emp where
        <if test="empName!=null and empName!=''">
            emp_name=#{empName}
        </if>
        <if test="age!=null and age!=''">
            and age=#{age}
        </if>
        <if test="gender!=null and gender!=''">
            and gender=#{gender}
        </if>
    </select>


2.where

where和if一般结合使用:a>若where标签中的if条件都不满足,则where标签没有任何功能,即不会添加where关键字b>若where标签中的if条件满足,则where标签会自动添加where关键字,并将条件最前方多余的and去掉注意:where标签不能去掉条件最后多余的and

  <select id="getEmpByCondition" resultType="Emp">
        select * from t_emp
        <where>
            <if test="empName!=null and empName!=''">
                emp_name=#{empName}
            </if>
            <if test="age!=null and age!=''">
                and age=#{age}
            </if>
            <if test="gender!=null and gender!=''">
                and gender=#{gender}
            </if>
        </where>

    </select>


3.trim

trim用于去掉或添加标签中的内容常用属性:prefix:在trim标签中的内容的前面添加某些内容prefixOverrides:在trim标签中的内容的前面去掉某些内容suffix:在trim标签中的内容的后面添加某些内容suffixOverrides:在trim标签中的内容的后面去掉某些内容

 <select id="getEmpByCondition" resultType="Emp">
        select * from t_emp where
        <if test="empName!=null and empName!=''">
            emp_name=#{empName}
        </if>
        <if test="age!=null and age!=''">
            and age=#{age}
        </if>
        <if test="gender!=null and gender!=''">
            and gender=#{gender}
        </if>
    </select>


4.choose、when、otherwise

choose、when、 otherwise相当于if, else if, else

场景:有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用

  <select id="getEmpByChoose" resultType="Emp">
        select * from t_emp
        <where>
            <choose>
                <when test="empName!=null and empName!=''">
                    emp_name=#{empName}
                </when>
                <when test="age!=null and age!=''">
                    age=#{age}
                </when>
                <when test="gender!=null and gender!=''">
                    and gender=#{gender}
                </when>

            </choose>
        </where>
    </select>



5.foreach

<!--    void insertMoreEmp(@Param("emps") List<Emp> emps);-->
    <insert id="insertMoreEmp">
        insert into t_emp values
<!--
    collection:设置当前要循环的集合
    item
-->
        <foreach collection="emps" item="emp" separator=",">
            (null,#{emp.empName},#{emp.age},#{emp.gender},null)
        </foreach>

    </insert>

<!--   void deleteMoreEmp(@Param("empIds") Integer[] empIds); -->
    <delete id="deleteMoreEmp">
<!--        delete from t_emp where emp_id in-->
<!--        (-->
<!--        <foreach collection="empIds" item="empId" separator=",">-->
<!--            #{empId}-->
<!--        </foreach>-->
<!--        )-->
        delete from t_emp where emp_id in
<!--        以open值开始,以close值结束-->
        <foreach collection="empIds" item="empId" separator="," open="(" close=")">
            #{empId}
        </foreach>
    </delete>


6.SQL标签

sql片段,可以记录一段公共sql片段,在使用的地方通过include标签进行引入

 <sql id="empColumns">
        emp_id,emp_name,gender,dept_id
    </sql>
    <select id="getEmpByConditionTwo" resultType="Emp">
        select <include refid="empColumns"></include> from t_emp
        <trim prefix="where" suffixOverrides="and">
            <if test="empName!=null and empName!=''">
                emp_name=#{empName}
            </if>
            <if test="age!=null and age!=''">
                and age=#{age}
            </if>
            <if test="gender!=null and gender!=''">
                and gender=#{gender}
            </if>
        </trim>

    </select>



八.Mybatis缓存

1.MyBatis的一级缓存(默认开启)

一级缓存是SqlSession级别的,即通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问

  • 使一级缓存失效的四种情况:

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

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

同一个SqlSession两次查询期间执行了任何一次增删改操作(任意增删改是会清空缓存的)

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

2.MyBatis的二级缓存

二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取

  • 二级缓存开启的条件:

a>在核心配置文件中,设置全局配置属性cacheEnabled="true",默认为true,不需要设置

b>在映射文件中设置标签

c>二级缓存必须在SqlSession关闭或提交之后有效

d>查询的数据所转换的实体类类型必须实现序列化的接口

使二级缓存失效的情况:

两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效

3.二级缓存的相关配置(了解即可)

在mapper配置文件中添加的cache标签可以设置一些属性:

①eviction属性:缓存回收策略,默认的是 LRU。

LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象。

FIFO(First in First out) – 先进先出:按对象进入缓存的顺序来移除它们。

SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。

WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

②flushInterval属性:刷新间隔,单位毫秒

默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新

③size属性:引用数目,正整数

代表缓存最多可以存储多少个对象,太大容易导致内存溢出

④readOnly属性:只读, true/false

true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了 很重要的性能优势。

false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。

4.MyBatis缓存查询的顺序(大-》小)

先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。

如果二级缓存没有命中,再查询一级缓存(一级缓存关闭或提交后才保存到二级缓存,因此一级缓存有的二级缓存不一定有)

如果一级缓存也没有命中,则查询数据库

SqlSession关闭之后,一级缓存中的数据会写入二级缓存

5.整合第三方缓存EHCache(针对二级缓存)

(1) 添加依赖

<!-- Mybatis EHCache整合包 -->
<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.2.1</version>
</dependency>
<!-- slf4j日志门面的一个具体实现 -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>


(2) 各jar包功能

jar包名称 作用
mybatis-ehcache Mybatis和EHCache的整合包
ehcache EHCache核心包
slf4j-api SLF4J日志门面包
logback-classic 支持SLF4J门面接口的一个具体实现

(3) 创建EHCache的配置文件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="D:\atguigu\ehcache"/>
	<defaultCache
        maxElementsInMemory="1000"
        maxElementsOnDisk="10000000"
        eternal="false"
        overflowToDisk="true"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU">
	</defaultCache>
</ehcache>


(4) 设置二级缓存的类型

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>


(5) 加入logback日志

存在SLF4J时,作为简易日志的log4j将失效,此时我们需要借助SLF4J的具体实现logback来打印日志。 创建logback的配置文件logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
	<!-- 指定日志输出的位置 -->
	<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
		<encoder>
            <!-- 日志输出的格式 -->
            <!-- 按照顺序分别是: 时间、日志级别、线程名称、打印日志的类、日志主体内容、换行-->
			<pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger][%msg]%n</pattern>
		</encoder>
	</appender>
    <!-- 设置全局日志级别。日志级别按顺序分别是: DEBUG、INFO、WARN、ERROR -->
    <!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 -->
    <root level="DEBUG">
		<!-- 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender -->
		<appender-ref ref="STDOUT" />
	</root>
	<!-- 根据特殊需求指定局部日志级别 -->
	<logger name="com.atguigu.crowd.mapper" level="DEBUG"/>
</configuration>


(6) EHCache配置文件说明

属性名 是否必须 作用
maxElementsInMemory 在内存中缓存的element的最大数目
maxElementsOnDisk 在磁盘上缓存的element的最大数目,若是0表示无穷大
eternal 设定缓存的elements是否永远不过期。 如果为true,则缓存的数据始终有效, 如果为false那么还要根据timeToIdleSeconds、timeToLiveSeconds判断
overflowToDisk 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
timeToIdleSeconds 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时, 这些数据便会删除,默认值是0,也就是可闲置时间无穷大
timeToLiveSeconds 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
diskSpoolBufferSizeMB DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区
diskPersistent 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。
diskExpiryThreadIntervalSeconds 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s, 相应的线程会进行一次EhCache中数据的清理工作
memoryStoreEvictionPolicy 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。 默认是LRU (最近最少使用),可选的有LFU (最不常使用)和FIFO (先进先出)

九、MyBatis的逆向工程

正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。 Hibernate是支持正向工

程的。

逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源:

  • Java实体类

  • Mapper接口

  • Mapper映射文件

1.创建逆向工程的步骤

①添加依赖和插件

<!-- 依赖MyBatis核心包 -->
<dependencies>
	<dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.7</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>
	<dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.16</version>
	</dependency>
</dependencies>
<!-- 控制Maven在构建过程中相关配置 -->
<build>
	<!-- 构建过程中用到的插件 -->
	<plugins>
		<!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 -->
		<plugin>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-maven-plugin</artifactId>
            <version>1.3.0</version>
			<!-- 插件的依赖 -->
			<dependencies>
				<!-- 逆向工程的核心依赖 -->
				<dependency>
                    <groupId>org.mybatis.generator</groupId>
                    <artifactId>mybatis-generator-core</artifactId>
                    <version>1.3.2</version>
				</dependency>
				<!-- MySQL驱动 -->
				<dependency>
                    <groupId>mysql</groupId>
                    <artifactId>mysql-connector-java</artifactId>
                    <version>8.0.16</version>
				</dependency>
			</dependencies>
		</plugin>
	</plugins>
</build>


②创建MyBatis的核心配置文件

③创建逆向工程的配置文件

文件名必须是:generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
	<!--
			targetRuntime: 执行生成的逆向工程的版本
                MyBatis3Simple: 生成基本的CRUD(清新简洁版)
                MyBatis3: 生成带条件的CRUD(奢华尊享版)
	-->
	<context id="DB2Tables" targetRuntime="MyBatis3">
		<!-- 数据库的连接信息 -->
		<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
						connectionURL="jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC"
						userId="root"
						password="123456">
		</jdbcConnection>
		<!-- javaBean的生成策略-->
		<javaModelGenerator targetPackage="com.atguigu.mybatis.pojo"targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
		</javaModelGenerator>
		<!-- SQL映射文件的生成策略 -->
		<sqlMapGenerator targetPackage="com.atguigu.mybatis.mapper"targetProject=".\src\main\resources">
			<property name="enableSubPackages" value="true" />
		</sqlMapGenerator>
		<!-- Mapper接口的生成策略 -->
		<javaClientGenerator type="XMLMAPPER"targetPackage="com.atguigu.mybatis.mapper" targetProject=".\src\main\java">
			<property name="enableSubPackages" value="true" />
		</javaClientGenerator>
        <!-- 逆向分析的表 -->
        <!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName -->
        <!-- domainObjectName属性指定生成出来的实体类的类名 -->
        <table tableName="t_emp" domainObjectName="Emp"/>
        <table tableName="t_dept" domainObjectName="Dept"/>
	</context>
</generatorConfiguration>


2、QBC查询

@Test
public void testMBG(){
    try {
		InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
		SqlSessionFactory sqlSessionFactory = new
		SqlSessionFactoryBuilder().build(is);
		SqlSession sqlSession = sqlSessionFactory.openSession(true);
		EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        //查询所有数据,条件为null查所有
        /*List<Emp> list = mapper.selectByExample(null);
        list.forEach(emp -> System.out.println(emp));*/
        //根据条件查询
        /*EmpExample example = new EmpExample();
        example.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThanOrEqualTo(20);
        example.or().andDidIsNotNull();
        //        选择性修改:修改时赋值为null不修改,而普通修改会直接把原值改为null
		List<Emp> list = mapper.selectByExample(example);
        list.forEach(emp -> System.out.println(emp));*/
        mapper.updateByPrimaryKeySelective(newEmp(1,"admin",22,null,"[email protected]",3));
	} catch (IOException e) {
		e.printStackTrace();
	}
}


十.分页插件

limit index,pageSize

pageSize:每页显示的条数

pageNum:当前页的页码

index:当前页的起始索引,index=(pageNum-1)*pageSize

count:总记录数

totalPage:总页数

totalPage = count / pageSize;

if(count % pageSize != 0){

totalPage += 1;

}

pageSize=4,pageNum=1,index=0 limit 0,4

pageSize=4,pageNum=3,index=8 limit 8,4

pageSize=4,pageNum=6,index=20 limit 8,4

首页 上一页 2 3 4 5 6 下一页 末页

1.添加分页插件依赖

<dependency>
<groupId>com.github.pagehelper</groupId>  
<artifactId>pagehelper</artifactId>
<version>5.2.0</version> //版本号
</dependency>


2.在mybatis-config.xml中创建分页插件

<plugins>
<!--分页插件-->
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>


3.查询操作测试

 @Test
    public void testPage(){
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
//        查询之前开启分页功能
        PageHelper.startPage(3,2);
        List<Emp> list = mapper.selectByExample(null);

//        查询之后获取分页相关的所有数据
//        list:分页之后的数据
//        navigatePages:导航分页的页码数
        PageInfo<Emp> pageInfo = new PageInfo<>(list, 5);
        list.forEach(System.out::println);
        System.out.println(pageInfo);
    }


4.分页相关数据

PageInfo{pageNum=3, pageSize=2, size=2, startRow=5, endRow=6, total=9, pages=5, list=Page{count=true, pageNum=3, pageSize=2, startRow=4, endRow=6, total=9, pages=5, reasonable=false, pageSizeZero=false}[Emp{empId=5, empName='a', age=null, gender='null', deptId=null}, Emp{empId=6, empName='a', age=null, gender='null', deptId=null}], prePage=2, nextPage=4, isFirstPage=false, isLastPage=false, hasPreviousPage=true, hasNextPage=true, navigatePages=5, navigateFirstPage=1, navigateLastPage=5, navigatepageNums=[1, 2, 3, 4, 5]}

pageNum:当前页的页码pageSize:每页显示的条数size:当前页显示的真实条数total:总记录数pages:总页数prePage:上一页的页码nextPage:下一页的页码isFirstPage/isLastPage:是否为第一页/最后一页hasPreviousPage/hasNextPage:是否存在上一页/下一页navigatePages:导航分页的页码数navigatepageNums:导航分页的页码,[1,2,3,4,5]

Mybatis的学习到这里先告一段落啦

有什么疑问可以在评论区提,文章中若有不当之处,也恳请各位帮忙指正

如果本文对铁子们有所帮助的话,可以一键三连哦

 

猜你喜欢

转载自blog.csdn.net/GANTENJ/article/details/130677010