Mybatis 的知识学习

准备:

maven:https://mvnrepository.com/

mybatis: MyBatis中文网

1.mybatis的定义

MyBatis 是一款优秀的持久层框架 ,它支持**自定义 SQL、存储过程以及高级映射。**MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

持久化:

  1. 持久化是将程序数据在持久状态和瞬时状态间转换的机制。(理解一下这个持久状态转化为瞬时状态,持久化是mybatis最重要的特性)。即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)
  2. 持久化的主要应用是将内存中的对象存储在数据库中,或者存储在磁盘文件中、XML数据文件中等等。JDBC就是一种持久化机制文件IO也是一种持久化机制。

为什么要持久化:

  1. **因为内存断点后数据会丢失,**但是有些业务不允许这种情况的存在。
  2. 比起硬盘,内存过于昂贵,如果有够量的内存,则不需要持久化服务,但是正是因为内存太贵,储存有限,因此需要持久化来缓存。

持久层:

  1. 完成持久化工作代码块,即Dao层
  2. 大多数情况下特别是企业级应用,数据持久化往往也就意味着将内存中的数据保存到磁盘上加以固化,而持久化的实现过程则大多通过各种关系数据库来完成。

mybatis的作用:

  1. Mybatis就是帮助程序员将数据存取到数据库里面。
  2. 传统的jdbc操作 ,**有很多重复代码块,简化开发 。**比如 : 数据取出时的封装 , 数据库的建立连接等等... , 通过框架可以减少重复代码,提高开发效率 。
  3. MyBatis 是一个半自动化的ORM框架 (Object Relationship Mapping) -->对象关系映射。
  4. 所有的事情,不用Mybatis依旧可以做到,只是用了它,会更加方便更加简单,开发更快速。

mybatis的优点:

  1. 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件就可以了,易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
  2. 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
  3. 解除sql与程序代码的耦合:通过提供DAO层 ,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
  4. 提供xml标签,支持编写动态sql。
  5. 现在主流使用方法。

2.搭建mybatis

地址:https://mvnrepository.com/artifact/org.mybatis

依赖:

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.8</version>
</dependency>

1.创建mysql数据库:

2.步骤

  1. 创建新项目,删除src

搭建环境(maven、数据库等)--->导入mybatis依赖-->编写java代码--->测试

  1. 导入mybatis依赖

Pom.xml:文件:

<?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">
    <parent>
        <artifactId>Mybatis-study</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>mybatis-01</artifactId>
    <!--    maven资源过滤-->
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>
</project>

mybatis的核心配置文件:连接数据的配置文件,包括账户、密码、时区、编码等配置。

<?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核心配置文件-->
<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?useSSl=trur&amp;sueUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

<!--    注册每一个mapper文件-->
    <mappers>
        <mapper resource="com/jiang/dao/UserMapper.xml"></mapper>
    </mappers>
    
</configuration>
  1. 创建新的模块

3.编写Mybatis的工具类:用于获取SqlSession对象:

package com.jiang.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

/**
 * @author Lenovo
 * @date 2024/3/16
 * @time 15:53
 * @project Mybatis-study
 **/
public class MybatisUtils {


    private static SqlSessionFactory sqlSessionFactory;

    static {
        //1. 获取mybatis-config的配置文件
        String resource = "mybatis-config.xml";
        try {
            // 2. 获得SqlSessionFactory工厂:
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //既然有了sqlSessionFactory,顾名思义,我们就可以从中获得sqlSession的实例了
    //3.sqlSession 完全包含了面向数据库执行SQL命令所需的所有方法
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }

}

4.编写java代码:

(一) 编写实体类:
package com.jiang.pojo;

/**
 * @author Lenovo
 * @date 2024/3/16
 * @time 15:59
 * @project Mybatis-study
 **/
public class User {

    private int id;
    private String name;
    private String pwd;

    public User() {
    }

    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}
(二) 编写Dao接口:
package com.jiang.dao;

import com.jiang.pojo.User;

import java.util.List;

/**
 * @author Lenovo
 * @date 2024/3/16
 * @time 16:00
 * @project Mybatis-study
 **/
public interface UserDao {

    List<User> getUserList();
}
(三) 编写mapper文件:
<?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">

//一定要指定namespace ,其次是注册mapper文件到mybatis-config文件中
<mapper namespace="com.jiang.dao.UserDao">
<!--    查询语句:id:是方法: resultType返回为User-->
    <select id="getUserList" resultType="com.jiang.pojo.User">
    select * from mybatis.user;
  </select>
</mapper>
  1. 编写测试类:

    package com.jiang.dao;

    import com.jiang.pojo.User;
    import com.jiang.utils.MybatisUtils;
    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;

    import java.util.List;

    /**

    • @author Lenovo

    • @date 2024/3/16

    • @time 16:10

    • @project Mybatis-study
      **/
      public class TetsDao {

      SqlSession sqlSession;
      @Test
      public void test(){
      try {
      sqlSession = MybatisUtils.getSqlSession();
      UserDao mapper = sqlSession.getMapper(UserDao.class);
      List<User> userList = mapper.getUserList();
      for (User user : userList) {
      System.out.println(user);
      }
      }catch (Exception e){
      e.printStackTrace();
      }finally {
      //关闭sqlSession
      sqlSession.close();
      }

      }
      }

(四) 总结:易错点:

mapper文件中: namespace 中 的名字要和 接口的路径地址和名字一致

mybatis-config文件中:

Pom.xml 文件中: maven的资源过滤要加上

    <!--    maven资源过滤-->
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>

3.CRUD

(一) 查
    List<User> getUserList();

    User getUserById(int id);

<!--    查询语句:resultType返回为User-->
    <select id="getUserList" resultType="com.jiang.pojo.User">
    select * from mybatis.user;
  </select>
    
<!--    根据id查询用户-->
    <select id="getUserById"  resultType="com.jiang.pojo.User" parameterType="int">
    select * from mybatis.user where id=#{id};
  </select>

id:表示sql语句操作方法的名字;

resultType: 表示返回的类型

parameter: 表示查询参数的类型

 SqlSession sqlSession;
    @Test
    public void test(){
        try {
            sqlSession = MybatisUtils.getSqlSession();
            UserDao mapper = sqlSession.getMapper(UserDao.class);
            List<User> userList = mapper.getUserList();
            for (User user : userList) {
                System.out.println(user);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            sqlSession.close();
        }

    }

    @Test
    public void getUserById(){
        sqlSession = MybatisUtils.getSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        User resultUser = mapper.getUserById(2);
        System.out.println(resultUser);
        sqlSession.close();
    }
(二) 增
 //增
    int addUser(User user);

    <insert id="addUser" parameterType="com.jiang.pojo.User">
        insert into mybatis.user (id,name,pwd) value (#{id},#{name},#{pwd})
    </insert>

 @Test
    public void addUser(){
        sqlSession = MybatisUtils.getSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        int resultNumber = mapper.addUser(new User(4, "哈哈", "1254adasd"));

        if (resultNumber > 0){
            System.out.println("插入成功");
        }

        //增删改都需要提交事务:
        sqlSession.commit();
        sqlSession.close();
    }
(三) 删
   //删
    int deleteUser(int id); //根据id 删除对象

删除操作:

    <delete id="deleteUser" parameterType="int">
        delete from mybatis.user where id=#{id}
    </delete>

    @Test
    public void deleteUser(){
        sqlSession = MybatisUtils.getSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);

        int i = mapper.deleteUser(4);

        if (i >0){
            System.out.println("删除操作成功");
        }

        //增删改都需要提交事务:
        sqlSession.commit();
        sqlSession.close();
    }
(四) 改
   //改
    int updateUser(User user); //传入一个User对象

    <update id="updateUser" parameterType="com.jiang.pojo.User">
        update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id};
    </update>

    @Test
    public void updateUser(){
        sqlSession = MybatisUtils.getSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        int resultNumber= mapper.updateUser(new User(4,"呵呵","454dsdsf"));

        if (resultNumber > 0){
            System.out.println("更新成功");
        }
        //增删改都需要提交事务:
        sqlSession.commit();
        sqlSession.close();
    }

4.Map传入参数

Map:

如果实体类或者数据库中表,字段,参数过多可以使用map集合。

    int addUser02(Map<String,Object> map);


//参数类型是map的类型
<insert id="addUser02" parameterType="map">
        insert into mybatis.user (id,name,pwd) value (#{userId},#{userName},#{userPwd})
    </insert>

    @Test
    public void addUser02(){
        sqlSession = MybatisUtils.getSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);

        HashMap<String, Object> map = new HashMap<String, Object>();
        map.put("userId","5");
        map.put("userName","hehe");
        map.put("userPwd","asfsd132123");
        int i = mapper.addUser02(map);
        if (i>0){
            System.out.println("添加一个用户成功");
        }

        //增删改都需要提交事务:
        sqlSession.commit();
        sqlSession.close();
    }
模糊查询:
  1. java代码传入通配符:%xxx%
  2. 在sql中拼接通配符 % xxx %

5.配置解析

mybatis核心配置文件:

(一) 环境配置:environments

MyBatis 可以配置成适应多种环境 ,这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有多种理由需要这么做。例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中使用相同的 SQL 映射。还有许多类似的使用场景。不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例 只能选择一种环境。

可以配置多个环境:

        <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?useSSl=trur&amp;sueUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>

mybatis默认使用的事务管理器是:JDBC, 默认使用的数据库连接池是POOLED

(二) 属性:Properties

这些属性可以在外部进行配置,并可以进行动态替换。

进行数据库连接的属性配置:

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSl=true;sueUnicode=true;characterEncoding=UTF-8;serverTimezone=Asia/Shanghai
username=root
password=root

在mybatis-config文件中替换掉数据库的配置使用${xxx} 来进行替换。

   <properties resource="db.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>

注意:

因此,通过方法参数传递的属性具有最高优先级,resource/url 属性中指定的配置文件次之最低 优先级的则是 properties 元素中指定的属性

(三) 设置:settings

设置日志

(四) 类型别名:typeAliases
  1. 给每一个实体类起别名 (在mybatis-config.xml中加入)

    <typeAliases> <typeAlias alias="Author" type="domain.blog.Author"/> <typeAlias alias="Blog" type="domain.blog.Blog"/> <typeAlias alias="Comment" type="domain.blog.Comment"/> <typeAlias alias="Post" type="domain.blog.Post"/> <typeAlias alias="Section" type="domain.blog.Section"/> <typeAlias alias="Tag" type="domain.blog.Tag"/> </typeAliases>
  2. 扫描包 (扫描一个包下面所有的类,java 会自动寻找Bean)

    <typeAliases> <package name="domain.blog"/> </typeAliases>
  3. 使用注解的方式

在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author;若有注解,则别名为其注解值

@Alias("author")
public class Author {
    ...
}

其他配置了解。

6.映射器(mappers)

作用:告诉 MyBatis 到哪里去找映射文件。

1.根据路径:(推荐使用)
<!-- 使用相对于类路径的资源引用 -->
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  <mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
2.根据class文件去绑定:

注意:但是接口 Dao 和它的Mapper文件 要在同一个包下,而且要同名。

<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
  <mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
3.通过包来去绑定:

注意:但是接口和它的Mapper文件要在同一个包下,而且要同名。

<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
  <package name="org.mybatis.builder"/>
</mappers>

7.作用域和生命周期:

不同作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题。

SqlSessionFactoryBuilder

这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。

SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 (一旦创建就一直存在)。

可以理解为:数据库连接池,一直存在,直到程序结束。

SqlSession

个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。

每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它 。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。

  1. 连接到连接池的一个请求。
  2. SqlSession 是线程不安全的,因此不可以被共享,所以最佳作用域是请求或者方法作用域。
  3. 用完之后需要关闭,否则资源被占用。

8.ResultMap(结果集映射)

一、解决实体类属性名和数据库字段名不一致的问题

User类中的password, 而数据库中的字段名是:pwd。

解决:

  1. 起别名
  2. 结果集映射:ResultMap

resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。

使用resultMap将实体类的属性名和数据库中的字段不一致解决掉:

    <resultMap id="userResultMap" type="User">
        <result property="userName" column="name"/>
        <result property="password" column="pwd"/>
    </resultMap>

    <select id="getUserList" resultMap="userResultMap">
    select * from mybatis.user;
    </select>

9.日志工厂

如果一个数据库操作,出现了异常,就需要排错,这时就可以使用日志工厂。

mybatis可以使用的日志:

SLF4J

LOG4J (需要手动配置一些东西才可以使用)

LOG4J2

JDK_LOGGING

COMMONS_LOGGING

STDOUT_LOGGING (mybatis默认使用的,不需要任何的配置)

设置日志:

使用STDOUT_LOGGING:

  <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

结果:

Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Opening JDBC Connection
Created connection 1433666880.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@55740540]
==>  Preparing: select * from mybatis.user; 
==> Parameters: 
<==    Columns: id, name, pwd
<==        Row: 1, 狂神, 123456
<==        Row: 2, 张三, abcdef
<==        Row: 3, 李四, 987654
<==        Row: 5, hehe, asfsd132123
<==      Total: 4
User{id=1, userName='狂神', password='123456'}
User{id=2, userName='张三', password='abcdef'}
User{id=3, userName='李四', password='987654'}
User{id=5, userName='hehe', password='asfsd132123'}
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@55740540]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@55740540]
Returned connection 1433666880 to pool.

使用LOG4j日志:

  1. mybatis-config.xml中配置好LOG4j

    <settings>
         <setting name="logImpl" value="LOG4j"/>
     </settings>
    
  2. Pom.xml中导入LOG4j的包的依赖

https://mvnrepository.com/artifact/org.apache.logging.log4j

<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
  1. resource目录下:配置一个log4j.properties文件

    priority :debug<info<warn<error

    #you cannot specify every priority with different file for log4j
    log4j.rootLogger=debug,stdout,info,debug,warn,error
    #console
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern= [%d{yyyy-MM-dd HH:mm:ss a}]:%p %l%m%n
    #info log
    log4j.logger.info=info
    log4j.appender.info=org.apache.log4j.DailyRollingFileAppender
    log4j.appender.info.DatePattern=''yyyy-MM-dd'.log'
    #存储在当前目录下的文件
    log4j.appender.info.File=./src/log/info.log
    log4j.appender.info.Append=true
    log4j.appender.info.Threshold=INFO
    log4j.appender.info.layout=org.apache.log4j.PatternLayout
    log4j.appender.info.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
    #debug log
    log4j.logger.debug=debug
    log4j.appender.debug=org.apache.log4j.DailyRollingFileAppender
    log4j.appender.debug.DatePattern='
    'yyyy-MM-dd'.log'
    log4j.appender.debug.File=./src/log/debug.log
    log4j.appender.debug.Append=true
    log4j.appender.debug.Threshold=DEBUG
    log4j.appender.debug.layout=org.apache.log4j.PatternLayout
    log4j.appender.debug.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
    #warn log
    log4j.logger.warn=warn
    log4j.appender.warn=org.apache.log4j.DailyRollingFileAppender
    log4j.appender.warn.DatePattern=''yyyy-MM-dd'.log'
    log4j.appender.warn.File=./src/log/warn.log
    log4j.appender.warn.Append=true
    log4j.appender.warn.Threshold=WARN
    log4j.appender.warn.layout=org.apache.log4j.PatternLayout
    log4j.appender.warn.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
    #error
    log4j.logger.error=error
    log4j.appender.error = org.apache.log4j.DailyRollingFileAppender
    log4j.appender.error.DatePattern='
    'yyyy-MM-dd'.log'
    log4j.appender.error.File = ./src/log/error.log
    log4j.appender.error.Append = true
    log4j.appender.error.Threshold = ERROR
    log4j.appender.error.layout = org.apache.log4j.PatternLayout
    log4j.appender.error.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n

4.写代码:

10.分页

实现limit分页: sql语句的用法

SELECT * FROM USER LIMIT startIndex, pageSize;

<resultMap id="userResultMap" type="User">
    <result property="userName" column="name"/>
    <result property="password" column="pwd"/>
</resultMap>

<select id="getUserByLimit"  parameterType="map" resultMap="userResultMap">
    select * from mybatis.user limit #{startIndex},#{pagaSize};
</select>

    @Test
    public void getUserByLimit(){

        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        //使用map
        HashMap<String, Object> map = new HashMap<String, Object>();
        map.put("startIndex",0);
        map.put("pagaSize",2);

        List<User> userList= mapper.getUserByLimit(map);
        for (User user : userList) {
            System.out.println(user);
        }

        sqlSession.close();
    }

11.使用注解开发:用来替代Mapper.xml

不推荐使用:还是建议使用mapper.xml的方式。

底层是反射机制和动态代理,不用使用Mapper文件;但是只能写简单的sql语句

@param("xxx") 以param中的参数名为查询字段;引用类型不需要加,只有一个基本类型的话也可以不加,但是建议加上。

package com.keafmd.dao;

import com.keafmd.domain.User;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import java.util.List;

/**
 * Keafmd
 *
 * @ClassName: IUserDao
 * @Description:
 * @author: 牛哄哄的柯南
 * @date: 2021-02-16 20:30
 */

/**
 * 在mybatis中针对CRUD一共有四个注解
 * @Select @Insert @Update @Delete
 */
public interface IUserDao {

    /**
     * 查询所有用户
     * @return
     */
    @Select("select * from user")
    List<User> findAll();

    /**
     * 保存用户
     * @param user
     */
    @Insert("insert into user(username,address,sex,birthday)values(#{username},#{address},#{sex},#{birthday})")
    void saveUser(User user);

    /**
     * 更新用户
     * @param user
     */
    @Update("update user set username=#{username},sex=#{sex},birthday=#{birthday},address=#{address} where id=#{id}")
    void updateUser(User user);

    /**
     * 删除用户
     * @param userId
     */
    @Delete("delete from user where id=#{id}")
    void deleteUser(Integer userId);

    /**
     * 根据id查询用户
     * @param userId
     * @return
     */
    @Select("select * from user where id=#{id}")
    User findById(Integer userId);

    /**
     * 根据用户名称模糊查询
     * @param username
     * @return
     */
    //@Select("select * from user where username like #{username}") //占位符
    @Select("select * from user where username like '%${value}%'")  //字符串拼接
    List<User> findByName(String username);

    /**
     * 查询总数量
     * @return
     */
    @Select("select count(*) from user")
    int findTotal();

}

自动提交事务:

12.Lombok的使用:

  1. 第一步安装lombok的插件

  2. 第二步导入lombok的依赖

    <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.30</version> <scope>provided</scope> </dependency>

常用的注解:

@Data

**@Data最常用的注解之一。**注解在类上,提供该类所有属性的getter/setter方法,还提供了equals、canEqual、hashCode、toString方法。

@Log4j

作用于类上,为该类提供一个属性名为log的log4j日志对象。

@AllArgsConstructor

作用于类上,为该类提供一个包含全部参的构造方法,注意此时默认构造方法不会提供。

@NoArgsConstructor

作用于类上,**提供一个无参的构造方法。**可以和@AllArgsConstructor同时使用,此时会生成两个构造方法:无参构造方法和全参构造方法。

不建议使用

13.复杂操作:

结果映射(resultMap)
  • constructor - 用于在实例化类时,注入结果到构造方法中
    • idArg - ID 参数;标记出作为 ID 的结果可以帮助提高整体性能
    • arg - 将被注入到构造方法的一个普通结果
  • id -- 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能
  • result -- 注入到字段或 JavaBean 属性的普通结果
  • association -- 一个复杂类型的关联;许多结果将包装成这种类型
    • 嵌套结果映射 -- 关联可以是 resultMap 元素,或是对其它结果映射的引用
  • collection -- 一个复杂类型的集合
    • 嵌套结果映射 -- 集合可以是 resultMap 元素,或是对其它结果映射的引用
  • discriminator -- 使用结果值来决定使用哪个 resultMap
    • case -- 基于某些值的结果映射
      • 嵌套结果映射 -- case 也是一个结果映射,因此具有相同的结构和元素;或者引用其它的结果映射

id和result的属性:

|--------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 属性 | 描述 |
| property | 映射到列结果的字段或属性。如果 JavaBean 有这个名字的属性(property),会先使用该属性。否则 MyBatis 将会寻找给定名称的字段(field)。 无论是哪一种情形,你都可以使用常见的点式分隔形式进行复杂属性导航。 比如,你可以这样映射一些简单的东西:"username",或者映射到一些复杂的东西上:"address.street.number"。 |
| column | 数据库中的列名,或者是列的别名。一般情况下,这和传递给 resultSet.getString(columnName) 方法的参数一样。 |
| javaType | 一个 Java 类的全限定名,或一个类型别名(关于内置的类型别名,可以参考上面的表格)。 如果你映射到一个 JavaBean,MyBatis 通常可以推断类型。然而,如果你映射到的是 HashMap,那么你应该明确地指定 javaType 来保证行为与期望的相一致。 |
| jdbcType | JDBC 类型,所支持的 JDBC 类型参见这个表格之后的"支持的 JDBC 类型"。 只需要在可能执行插入、更新和删除的且允许空值的列上指定 JDBC 类型。这是 JDBC 的要求而非 MyBatis 的要求。如果你直接面向 JDBC 编程,你需要对可以为空值的列指定这个类型。 |
| typeHandler | 我们在前面讨论过默认的类型处理器。使用这个属性,你可以覆盖默认的类型处理器。 这个属性值是一个类型处理器实现类的全限定名,或者是类型别名。 |

ofType: 指代泛型的类型;

关联:association ;关联查询的时候

<resultMap id="blogResult" type="Blog">
  <association property="author" column="author_id" javaType="Author" select="selectAuthor"/>
</resultMap>

<select id="selectBlog" resultMap="blogResult">
  SELECT * FROM BLOG WHERE ID = #{id}
</select>

<select id="selectAuthor" resultType="Author">
  SELECT * FROM AUTHOR WHERE ID = #{id}
</select>
(一) 多对一的关系:

例子:多个学生对一个老师

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核心配置文件-->
<configuration>
<!--    配置数据库连接-->
    <properties resource="db.properties"/>
<!--    设置日志-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

<!--    起别名:-->
    <typeAliases>
        <typeAlias type="com.jiang.pojo.Teacher" alias="Teacher"/>
        <typeAlias type="com.jiang.pojo.Student" alias="Student"/>
    </typeAliases>
    <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>

        <environment id="test">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSl=trur&amp;sueUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>

    </environments>

<!--    注册每一个mapper文件-->
    <mappers>
       <mapper class="com.jiang.dao.studentMapper"/>
        <mapper class="com.jiang.dao.teacherMapper"/>
    </mappers>

</configuration>

package com.jiang.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author Lenovo
 * @date 2024/3/20
 * @time 15:22
 * @project Mybatis-study
 **/

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {

    private int id;
    private String name;
    private Teacher teacher;

}




package com.jiang.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author Lenovo
 * @date 2024/3/20
 * @time 15:22
 * @project Mybatis-study
 **/

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {

    private int id;
    private String name;
}

package com.jiang.dao;

import com.jiang.pojo.Student;
import java.util.List;

/**
 * @author Lenovo
 * @date 2024/3/20
 * @time 15:13
 * @project Mybatis-study
 **/
public interface studentMapper {

    //获取所有学生及对应老师的信息
    List<Student> getStudents();
}

查询嵌套处理: 按照查询进行嵌套处理就像SQL中的子查询

<?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.jiang.dao.studentMapper">

    <!--
        需求:获取所有学生及对应老师的信息
    思路:
    1. 获取所有学生的信息
    2. 根据获取的学生信息的老师ID->获取该老师的信息
    3. 思考问题,这样学生的结果集中应该包含老师,该如何处理呢,数据库中我们一般使用关联查询?
        1. 做一个结果集映射:StudentTeacher
        2. StudentTeacher结果集的类型为 Student
        3. 学生中老师的属性为teacher,对应数据库中为tid。
           多个 [1,...)学生关联一个老师=> 一对一,一对多
        4. 查看官网找到:association -- 一个复杂类型的关联;使用它来处理关联查询
-->
    <select id="getStudents" resultMap="TeacherStudents">
        select  * from student
    </select>
    <resultMap id="TeacherStudents" type="Student">
        <!--association关联属性 property属性名 javaType:返回的属性类型
        column在多的一方的表中的列名
        select:表示执行的子查询操作名:
        -->
        <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
    </resultMap>

    <select id="getTeacher" resultType="Teacher">
        select * from teacher where id=#{id}
    </select>

</mapper>

测试:

package com.jiang.dao;

import com.jiang.pojo.Student;
import com.jiang.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

/**
 * @author Lenovo
 * @date 2024/3/20
 * @time 15:49
 * @project Mybatis-study
 **/
public class MyTest {


    @Test
    public void getStudents(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        studentMapper mapper = sqlSession.getMapper(studentMapper.class);
        List<Student> students = mapper.getStudents();
        for (Student student : students) {
            System.out.println(student);
        }
        sqlSession.close();
    }
}

按照结果嵌套处理:按照结果进行嵌套处理就像SQL中的联表查询

一次查询出所有的结果,将第二张表中的数据进行映射处理。

<!--    按结果映射-->
    <select id="getStudents2" resultMap="TeacherStudents2">
        select s.id sid,s.name sname,t.name tname from student s,
        teacher t where s.tid = t.id ;
    </select>
    <resultMap id="TeacherStudents2" type="Student">
        <id property="id" column="sid"/>
        <result property="name" column="sname"/>
        <!--关联对象property 关联对象在Student实体类中的属性-->
        <association property="teacher" javaType="Teacher">
<!--            properties: 是在实体中的名字,column是在数据库中的名字-->
            <result property="name" column="tname"/>
        </association>
    </resultMap>

    @Test
    public void getStudents2(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        studentMapper mapper = sqlSession.getMapper(studentMapper.class);
        List<Student> students2 = mapper.getStudents2();

        for (Student student : students2) {
            System.out.println(student);
        }
        sqlSession.close();
    }
(二) 一对多的关系:

例子:一个老师对应多个学生:关联使用collection

package com.jiang.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author Lenovo
 * @date 2024/3/20
 * @time 15:22
 * @project Mybatis-study
 **/

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {

    private int id;
    private String name;
    private int tid;

}



package com.jiang.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

/**
 * @author Lenovo
 * @date 2024/3/20
 * @time 15:22
 * @project Mybatis-study
 **/

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {

    private int id;
    private String name;
    private List<Student> students;
}

按查询映射:

<!--    1.按查询映射:-->

    <select id="getTeacher" resultMap="TeacherStudents">
        select * from teacher where id=#{id}
    </select>
    <resultMap id="TeacherStudents" type="Teacher">
<!--       集合
           column是一对多的外键 , 写的是一的主键的列名,就是teacher的id -->
        <collection property="students" column="id" javaType="ArrayList" 
          ofType="Student"
                    select="getStudentByTeacherId"/>
    </resultMap>
    <select id="getStudentByTeacherId" resultType="Student">
        select * from student where tid=#{id}
    </select>

ofType :是泛型的映射。

按结果进行映射:

<!--    2.按结果进行映射-->

    <select id="getTeacher2" resultMap="TeacherStudents2">
        select s.id sid, s.name sname,t.name tname, t.id tid from student s, teacher t
        where s.tid = t.id and t.id =#{id};
    </select>
    <resultMap id="TeacherStudents2" type="Teacher">
<!--        老师的信息-->
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
<!--        collection :返回学生的信息-->
        <collection property="students" ofType="Student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>

注意:

association是用于一对一和多对一,而collection是用于一对多的关系

JavaType和ofType都是用来指定对象类型的

  • JavaType是用来指定pojo中属性的类型
  • ofType指定的是映射到list集合属性中pojo的类型。

14.动态SQL:

准备:

package com.jiang.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

/**
 * @author Lenovo
 * @date 2024/3/20
 * @time 18:48
 * @project Mybatis-study
 **/

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Blog {

    private String id;
    private String title;
    private String author;
    private Date createTime;
    private int views;

}





package com.jiang.dao;

import com.jiang.pojo.Blog;

import java.util.List;

/**
 * @author Lenovo
 * @date 2024/3/20
 * @time 18:49
 * @project Mybatis-study
 **/
public interface BlogMapper {
    /**
     * 增加一个blog
     * @param blog
     * @return
     */
    int addBlog(Blog blog);

    List<Blog> getBlogList();
}

package com.jiang.utils;

import java.util.UUID;

/**
 * @author Lenovo
 * @date 2024/3/20
 * @time 18:47
 * @project Mybatis-study
 **/
public class IDutils {

    public static String getId(){
        return UUID.randomUUID().toString().replace("-","");
    }

}

<mapper namespace="com.jiang.dao.BlogMapper">

    <insert id="addBlog" parameterType="Blog">
        insert into mybatis.blog (id,title,author,create_time,views)
        values (#{id},#{title},#{author},#{createTime},#{views})
    </insert>

    <select id="getBlogList" resultType="Blog">
        select * from blog
    </select>
</mapper>

MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach
if:
<select id="findActiveBlogWithTitleLike"
  resultType="Blog">
  SELECT * FROM BLOG
  WHERE state = 'ACTIVE'
  <if test="title != null">
    AND title like #{title}
  </if>
</select>

    <select id="queryBlogByIf" resultType="Blog" parameterType="map">
        select * from blog where
        <if test="title !=null">
            title=#{title}
        </if>

        <if test="author !=null">
            and author=#{author}
        </if>
    </select>


    <select id="queryBlogByIf2" resultType="Blog" parameterType="map">
        select * from blog
        <where>
            <if test="title !=null">
                title=#{title}
            </if>
            <if test="author !=null">
                and author=#{author}
            </if>
        </where>
    </select>

同义替换:where会自动去除and 或者or

select * from blog
<where>
  <if test="title != null">
    title = #{title}
  </if>
  <if test="author != null">
    and author = #{author}
  </if>
</where>

    @Test
    public void queryBlogByIf(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap<String, String> map = new HashMap<String, String>();
        map.put("title","Mybatis如此简单");
        map.put("author","狂神说");
        List<Blog> blogs = mapper.queryBlogByIf(map);

        for (Blog blog : blogs) {
            System.out.println(blog);
        }
        sqlSession.close();
    }
trim:
  1. where: 条件判断的语句

    <select id="findActiveBlogLike" resultType="Blog">
    SELECT * FROM BLOG
    WHERE
    <if test="state != null">
    state = #{state}
    </if>
    <if test="title != null">
    AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
    AND author_name like #{author.name}
    </if>
    </select>

  2. SET: 用于动态更新语句的类似解决方案叫做 setset 元素可以用于动态包含需要更新的列,忽略其它不更新的列. (更新语句update时,去使用

    <update id="updateAuthorIfNecessary"> update Author <set> <if test="username != null">username=#{username},</if> <if test="password != null">password=#{password},</if> <if test="email != null">email=#{email},</if> <if test="bio != null">bio=#{bio}</if> </set> where id=#{id} </update>

更新操作:

  int updateBlog(Map map);

<!--    更新语句-->
    <update id="updateBlog" parameterType="map">
        update blog
        <set>
            <if test="title !=null">
                title=#{title},
            </if>
            <if test="author !=null">
                author=#{author}
            </if>
        </set>
        where  id=#{id}
    </update>

    @Test
    public void updateBlog(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap<String, String> map = new HashMap<String, String>();
        map.put("title","python如此简单");
        map.put("author","小明");
        map.put("id","f7d6ccc28b3a4882adeb86726d354698");

        mapper.updateBlog(map);
        sqlSession.close();
    }
choose:

有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用 MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

<select id="findActiveBlogLike"
  resultType="Blog">
  SELECT * FROM BLOG WHERE state = 'ACTIVE'
  <choose>
    <when test="title != null">
      AND title like #{title}
    </when>
    <when test="author != null and author.name != null">
      AND author_name like #{author.name}
    </when>
    <otherwise>
      AND featured = 1
    </otherwise>
  </choose>
</select>
foreach:
动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候).

它允许你指定一个集合,声明可以在元素体内使用的集合项(item) 和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符。separator 是分割符。

<select id="selectPostIn" resultType="domain.blog.Post">
  SELECT *
  FROM POST P
  WHERE ID in
  <foreach item="item" index="index" collection="list"
      open="(" separator="," close=")">
        #{item}
  </foreach>
</select>

(item1, item2, item3, ....)

collection:是一个list集合类型。

sql标签:抽取公共的部分,在使用的部分使用include包含。

<sql>
    <if test="state != null">
      state = #{state}
    </if>
    <if test="title != null">
      AND title like #{title}
    </if>
</sql>

例子:

    List<Blog> getBlogListByForEach(Map map);

    <select id="getBlogListByForEach" parameterType="map" resultType="Blog">

        select * from blog 
        <where>
            <!--
          collection:指定输入对象中的集合属性的名字
          item:每次遍历生成的对象
          open:开始遍历时的拼接字符串
          close:结束时拼接的字符串
          separator:遍历对象之间需要拼接的字符串
          select * from blog where 1=1 and (id=1 or id=2 or id=3)
        -->
            <foreach collection="ids" item="id" open="and (" close=")"
            separator="or">
                id=#{id}
            </foreach>
        </where>
    </select>

select * from blog where 1=1 and (id=1 or id=2 or id=3) :执行的sql语句,拼接sql语句。

    @Test
    public void testForEach(){

        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap<String, List> map = new HashMap<String, List>();
        ArrayList<Integer> idList = new ArrayList<Integer>();
        idList.add(1);
        idList.add(2);
        idList.add(3);
        map.put("ids",idList);

        List<Blog> blogList = mapper.getBlogListByForEach(map);
        for (Blog blog : blogList) {
            System.out.println(blog);
        }
        sqlSession.close();

    }

14.缓存

MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。

缓存 (只有查询操作才会使用缓存):一次查询的结果,暂时将数据存储到内存中,不需要再次连接数据库,减少系统性能的开销问题。

数据库中重要的概念:读写分离,主从复制原理。

mybatis中的缓存:
  1. 一级缓存 也叫本地缓存,如果两次查询的结果都是一样的,那么就直接在本地缓存读取,不在再次连接数据库进行查询。 (自动开启)sqlSession。 增删改操作可能会改变数据,所以会刷新缓存。

注意:一级缓存默认是开启的,只在一次sqlSession中才有效,也就是拿到这个数据区间才会有效果。

  1. 二级缓存 (全局缓存,手动开启)

二级缓存生效: 只有 一级缓存结束后,将缓存内容存储到二级缓存中,二级缓存会去开启。开启了二级缓存,缓存只在一个mapper中生效

(1)mybatis-config.xml中开启全局缓存:

<setting name="cacheEnabled" value="true"/>

(2) 要启用全局的二级缓存,只对一个Mapper文件有效果 , 可以自定义缓存的规则

<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

mybatis可用的清除策略有:

  • LRU -- 最近最少使用:移除最长时间不被使用的对象。
  • FIFO -- 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT -- 软引用:基于垃圾回收器状态和软引用规则移除对象。
  • WEAK -- 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。

默认的清除策略是 LRU。

mybatis 缓存原理:

用户首先会查询二级缓存,如果二级缓存没有接着会查询一级缓存;最后如果缓存中都没有数据就会查询数据库

mybatis 自定义缓存:(了解)

除了上述自定义缓存的方式,你也可以通过实现你自己的缓存,或为其他第三方缓存方案创建适配器,来完全覆盖缓存行为。

Ehcache : Java开源的分布式缓存,是一种通用的缓存。
<cache type="com.domain.something.MyCustomCache"/>

自定义:

type 属性指定的类必须实现 org.apache.ibatis.cache.Cache 接口,
且提供一个接受 String 参数作为 id 的构造器。 

public interface Cache {
  String getId();
  int getSize();
  void putObject(Object key, Object value);
  Object getObject(Object key);
  boolean hasKey(Object key);
  Object removeObject(Object key);
  void clear();
}
相关推荐
xlsw_3 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
南宫生5 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
sanguine__5 小时前
Web APIs学习 (操作DOM BOM)
学习
数据的世界017 小时前
.NET开发人员学习书籍推荐
学习·.net
四口鲸鱼爱吃盐7 小时前
CVPR2024 | 通过集成渐近正态分布学习实现强可迁移对抗攻击
学习
OopspoO9 小时前
qcow2镜像大小压缩
学习·性能优化
A懿轩A10 小时前
C/C++ 数据结构与算法【栈和队列】 栈+队列详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·栈和队列
居居飒10 小时前
Android学习(四)-Kotlin编程语言-for循环
android·学习·kotlin
kkflash310 小时前
提升专业素养的实用指南
学习·职场和发展
cmdch201710 小时前
Mybatis加密解密查询操作(sql前),where要传入加密后的字段时遇到的问题
数据库·sql·mybatis