Mybatis

Mybatis

简介

  • 持久层框架
    • 把一些东西长久得存下来
  • 将数据存入数据库
  • 没有也行,有了更方便

依赖

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.9</version>
</dependency>

优点

  • SQL与代码分离
  • 提供映射标签,支持与数据库字段关系映射
  • 提供对象关系映射标签
  • 提供XML标签,可编写动态SQL

HelloWorld

  • *Mapper.xml
    • resultType
      • 返回单个对象
    • resultMap
      • 返回多个对象

初始配置与实现

数据库表构造

CREATE DATABASE `mybatis`;

USE `mybatis`;

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
`id` int(20) NOT NULL,
`name` varchar(30) DEFAULT NULL,
`pwd` varchar(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert  into `user`(`id`,`name`,`pwd`) values (1,'狂神','123456'),(2,'张三','abcdef'),(3,'李四','987654');

流程:

  1. pom.xml
  2. MybatisUtil.java
  3. mybatis-config.xml
  4. User.java
  5. UserDao.java
  6. UserMapper.xml
  7. Test.java

pom.xml

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.9</version>
</dependency>
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.0.32</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>RELEASE</version>
    <scope>test</scope>
</dependency>

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.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?autoReconnect=true&amp;useUnicode=true&amp;characterEncoding=utf8&amp;serverTimezone=GMT%2B8"/>
                <property name="username" value="root"/>
                <property name="password" value="lu123"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="com/lu/dao/UserMapper.xml"/>
    </mappers>
</configuration>

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.lu.dao.UserDao">
    <select id="getUserList" resultType="com.lu.pojo.User">
        select * from mybatis.user
    </select>
</mapper>

MybatisUtil.java

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;

public class MyBatisUtil {
    private static SqlSessionFactory factory;

    static {
        try {
            String resource = "mybatis-config.xml";
            InputStream is = Resources.getResourceAsStream(resource);
            factory = new SqlSessionFactoryBuilder().build(is);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static SqlSession getSqlSession() {
        return factory.openSession();
    }
}

测试

public class UserDaoTest {
    @Test
    public void test() {
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        for (User user : userDao.getUserList()) {
            System.out.println(user);
        }
        sqlSession.close();
    }
}

Map妙用

  • 可以脱离变量命名的束缚
  • 当变量很多时,便于操作
User getUserByMap(Map<String, Object> map);
<select id="getUserByMap" parameterType="map" resultType="com.lu.pojo.User">
    select * from mybatis.user where id = #{id} and name = #{name}
</select>
@Test
public void test06() {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    Map<String, Object> map = new HashMap<>();
    map.put("id", 1);
    map.put("name", "lct");
    System.out.println(userMapper.getUserByMap(map));
    sqlSession.close();
}

模糊查询

List<User> getUserThroughBlurSearch(String name);
<select id="getUserThroughBlurSearch" parameterType="string" resultType="com.lu.pojo.User">
    select * from mybatis.user where name like #{name}
</select>
@Test
public void test07() {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    for (User user : userMapper.getUserThroughBlurSearch("%李%")) {
        System.out.println(user);
    } 
    sqlSession.close();
}

问题

增删改未能生效

  • 需要提交事务
  • commit

XML读取不到

pom.xml中添加语句

<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <excludes>
                <exclude>**/*.properties</exclude>
                <exclude>**/*.xml</exclude>
            </excludes>
            <filtering>false</filtering>
        </resource>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
</build>

配置解析

mybatis-config.xml

标签顺序

properties?
settings?
typeAliases?
typeHandlers?
objectFactory?
objectWrapperFactory?
reflectorFactory?
plugins?
environments?
databaseIdProvider?
mappers

环境配置

environments

  • 尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境

属性

properties

  • 可以在外部进行配置,并可以进行动态替换
  • 既可以在典型的 Java 属性文件中配置这些属性
  • 也可以在 properties 元素的子元素中设置

properties样例

# 这里的优先使用
driver = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/mybatis?autoReconnect=true&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
username = root
password = lu123
<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>
</environments>

类型别名

typeAliases

  • 设置一个短一点的名字
  • 一个包扫描之后,它里面的类无法再起别名
    • 因此样例中只能选其一,另一个需要注释掉

typeAliases样例

  <typeAliases>
      <package name="com.lu.pojo"/>
      <typeAlias type="com.lu.pojo.User" alias="user"/>
  </typeAliases>

或者

@Alias("") // 扫描包后通过注解起别名

设置

settings

  • logImpl
    • 指定 MyBatis 所用日志的具体实现,未指定时将自动查找
    • SLF4J | LOG4J(3.5.9 起废弃) | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING

生命周期和作用域

SqlSessionFactoryBuilder

一旦创建了 SqlSessionFactory,就不再需要SqlSessionFactoryBuilder了

  • 最佳作用域是方法作用域(也就是局部方法变量)

SqlSessionFactory

SqlSessionFactory就是数据库连接池,一旦创建就要一直存在,不要反复创建

  • 最佳作用域是应用作用域(全局)

SqlSession

  • 连接到连接池的一个请求
  • 用完之后需要关闭
  • 最佳作用域是方法作用域(也就是局部方法变量)

resultMap

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

  • 就很强大
  • 要是人们不和也可以这样解决就好了
// 数据库中,密码列名为:pwd
public class User {
    private int id;  //id
    private String name;   //姓名
    private String password;   //密码
}
<mapper namespace="com.lu.dao.UserMapper">
    <resultMap id="UserMap" type="user">
        <result column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="pwd" property="password"/>
    </resultMap>

    <select id="getUserList" resultMap="UserMap">
        select * from mybatis.user
    </select>
</mapper>

日志

<dependency>
   <groupId>log4j</groupId>
   <artifactId>log4j</artifactId>
   <version>1.2.17</version>
</dependency>

log4j.properties

log4j.rootLogger=DEBUG,console,file

log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n

log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/lu.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n

log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
  • mybatis 3.5.9之后无法使用log4j
  • log4j2用不来
  • 所以摆了
  • 但把mybatis降级后可以用,所以还是没摆
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.7</version>
</dependency>

使用

<settings>
    <setting name="logImpl" value="LOG4J"/>
</settings>
static Logger logger = Logger.getLogger(UserDaoTest.class);

@Test
public void test02() {
    logger.info("info: enter");
    logger.debug("debug: enter");
    logger.error("error: enter");
}

分页

  • 减少数据处理量
List<User> getUserByLimit(Map<String, Object> map);
<select id="getUserByLimit" resultMap="UserMap" parameterType="map">
    select * from mybatis.user limit #{idx}, #{size}
</select>
@Test
public void test03() {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    Map<String, Object> map = new HashMap<>();
    map.put("idx", 0);
    map.put("size", 3);
    List<User> users = mapper.getUserByLimit(map);
    for (User user : users) {
        System.out.println(user);
    }
    sqlSession.close();
}

面向接口开发

@Select("select * from user")
List<User> getUserList();
<mappers>
    <mapper class="com.lu.dao.UserMapper"/>
</mappers>
@Test
public void test() {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    for (User user : mapper.getUserList()) {
        System.out.println(user);
    }
    sqlSession.close();
}
  • 基本数据类型对于变量名建议加上@Param("")
  • 引用类型不需要加
    • 类(class)、 接口(interface)、数组(array)

#与$的区别

#{} 的作用主要是替换预编译语句(PrepareStatement)中的占位符(?)

INSERT INTO user (name) VALUES (#{name});
INSERT INTO user (name) VALUES (?);

${} 的作用是直接进行字符串替换

INSERT INTO user (name) VALUES ('${name}');
INSERT INTO user (name) VALUES ('kuangshen');

执行流程

  1. Resources获取加载全局配置文件
  2. 实例化SqlSessionFactoryBuilder构造器
  3. 解析配置文件流XMLConfigBuilder
  4. Configuration所有的配置信息
  5. SqlSessionFactory实例化
  6. transactionCacheManager事务缓存管理器
  7. 创建executor执行器
  8. 创建SqlSession
  9. Mapper,实现CRUD
    1. 若失败,返回6
    2. 若成功,提交事务,到10
  10. 关闭

Lombok

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.24</version>
    <scope>provided</scope>
</dependency>
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private String pwd;
}

多对一

  • 集合:collection
    • 对象集合:ofType
  • 对象:association
  • 归根结底就是处理对象和数据库之间的字段属性冲突

初始

用到的表

CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老师');

CREATE TABLE `student` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fktid` (`tid`),
CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');

实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private int id;
    private String name;
    private Teacher teacher;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
    private int id;
    private String name;
}

查询嵌套方式

List<Student> getStudent();
<resultMap id="stuMap" type="student">
    <association property="teacher" column="tid" javaType="teacher" select="getTeacher"/>
</resultMap>
<select id="getStudent" resultMap="stuMap">
    select * from mybatis.student
</select>
<select id="getTeacher" resultType="teacher">
    select * from mybatis.teacher where id = #{tid}
</select>

结果嵌套方式

List<Student> getStudentByResult();
<resultMap id="stuResult" type="student">
    <result property="id" column="sid"/>
    <result property="name" column="sname"/>
    <association property="teacher" javaType="teacher">
        <result property="name" column="tname"/>
    </association>
</resultMap>
<select id="getStudentByResult" resultMap="stuResult">
    select s.id sid, s.name sname, t.name tname
    from mybatis.student s, mybatis.teacher t
    where s.tid = t.id
</select>
  • 查询嵌套不需要把类的所有属性表明,结果嵌套需要,否则对应对象的该属性会为空

一对多

初始

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private int id;
    private String name;
    private int tid;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
    private int id;
    private String name;
    private List<Student> students;
}

实现

Teacher getTeacher(@Param("tid") int id);
<resultMap id="teacherMap" type="teacher">
    <result property="id" column="t_id"/>
    <result property="name" column="tname"/>
    <collection property="students" ofType="student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="tid" column="tid"/>
    </collection>
</resultMap>
<select id="getTeacher" resultMap="teacherMap">
    select s.id sid, s.name sname, t.name tname, t.id t_id
    from mybatis.student s, mybatis.teacher t
    where s.tid = t.id and t.id = #{tid}
</select>
  • t.id 为什么不定义为tid
    • 如果那样定义的话,可能会与student库中的tid字段冲突
    • 并不会报错,但最好不要这样写,容易有歧义

动态SQL

根据不同的条件生成不同的SQL语句

  • 本质就是拼接SQL语句

初始化

CREATE TABLE `blog` (
`id` varchar(50) NOT NULL COMMENT '博客id',
`title` varchar(100) NOT NULL COMMENT '博客标题',
`author` varchar(30) NOT NULL COMMENT '博客作者',
`create_time` datetime NOT NULL COMMENT '创建时间',
`views` int(30) NOT NULL COMMENT '浏览量'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Blog {
    private String id;
    private String title;
    private String author;
    private Date createTime;
    private int views;
}
int addBlog(Blog blog);
<insert id="addBlog" parameterType="blog">
    insert into mybatis.blog values (#{id}, #{title}, #{author}, #{createTime}, #{views})
</insert>
@Test
public void test01() {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
  
    Blog blog = new Blog();
    blog.setId(IDUtil.getID());
    blog.setTitle("Mybatis如此简单");
    blog.setAuthor("lct");
    blog.setCreateTime(new Date());
    blog.setViews(9999);
    mapper.addBlog(blog);
    blog.setId(IDUtil.getID());
    blog.setTitle("Java如此简单");
    mapper.addBlog(blog);
    blog.setId(IDUtil.getID());
    blog.setTitle("Spring如此简单");
    mapper.addBlog(blog);
    blog.setId(IDUtil.getID());
    blog.setTitle("微服务如此简单");
    mapper.addBlog(blog);
  
    sqlSession.commit();
    sqlSession.close();
}

if

List<Blog> queryBlogIf(Map<String, Object> map);
<select id="queryBlogIf" parameterType="map" resultType="blog">
    select * from mybatis.blog
    <where>
        <if test="title != null">
            and title = #{title}
        </if>
        <if test="author != null">
            and author = #{author}
        </if>
    </where>
</select>
@Test
public void test02() {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    Map<String, Object> map = new HashMap<>();
    map.put("author", "lct");
    map.put("title", "Mybatis如此简单");
    for (Blog blog : mapper.queryBlogIf(map)) {
        System.out.println(blog);
    }
    sqlSession.close();
}

choose (when, otherwise)

  • 类似于Java中的switch语句
  • 样例中,虽然设置了author,但由于when的执行顺序,进行对比的依旧是title
List<Blog> queryBlogChoose(Map<String, Object> map);
<select id="queryBlogChoose" parameterType="map" resultType="blog">
    select * from mybatis.blog
    <where>
        <choose>
            <when test="title != null">
                and title = #{title}
            </when>
            <when test="author != null">
                and author = #{author}
            </when>
            <otherwise>
                and views >= 4000
            </otherwise>
        </choose>
    </where>
</select>
@Test
public void test03() {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    Map<String, Object> map = new HashMap<>();
    map.put("author", "lct");
    map.put("title", "Mybatis如此简单");
    for (Blog blog : mapper.queryBlogChoose(map)) {
        System.out.println(blog);
    }
    sqlSession.close();
}

trim (where, set)

  • where标签下的语句前面都加and最健壮

  • set标签下的语句后面都加,最健壮

  • trim是以上两个标签的底层实现

    • <trim prefix="WHERE" prefixOverrides="AND |OR ">
        ...
      </trim>
      
      <trim prefix="SET" suffixOverrides=",">
        ...
      </trim>
      
int updateBlog(Map<String, Object> map);
<update id="updateBlog" parameterType="map">
    update mybatis.blog
    <set>
        <if test="title != null">
            title = #{title},
        </if>
        <if test="author != null">
            author = #{author},
        </if>
    </set>
    <where>
        and id = #{id}
    </where>
</update>
@Test
public void test04() {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    Map<String, Object> map = new HashMap<>();
    map.put("author", "lct");
    map.put("title", "Mybatis如此简单");
    map.put("id", "4d08e2312bc3405195b2c581e63343f3");
    mapper.updateBlog(map);
    sqlSession.commit();
    sqlSession.close();
}

SQL片段

  • 将一些可重复使用的SQL语句存起来
  • 可以引入使用
  • 建议基于单表操作
  • 不要存在where标签
<sql id="if-title-author">
    <if test="title != null">
        and title = #{title}
    </if>
    <if test="author != null">
        and author = #{author}
    </if>
</sql>

<select id="queryBlogIf" parameterType="map" resultType="blog">
    select * from mybatis.blog
    <where>
        <include refid="if-title-author"/>
    </where>
</select>

foreach

List<Blog> queryBlogForeach(Map<String, Object> map);
<select id="queryBlogForeach" parameterType="map" resultType="blog">
    select * from mybatis.blog
    <where>
        id in
        <foreach item="id" collection="list" open="(" separator="," close=")">
            #{id}
        </foreach>
    </where>
</select>
@Test
public void test05() {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    Map<String, Object> map = new HashMap<>();
    List<String> list = new ArrayList<>();
    list.add("4d08e2312bc3405195b2c581e63343f3");
    list.add("5bf1b702d0df46d4970ff7401e026345");
    map.put("list", list);
    for (Blog blog : mapper.queryBlogForeach(map)) {
        System.out.println(blog);
    }
    sqlSession.close();
}

缓存

  • 一次查询的结果暂存到一个可以直接读取的地方
  • 再次查询相同数据就去取就可以,不用走数据库

适用于:经常需要查询但几乎不会改变的数据

最终目的:提高查询效率

一级缓存

相当于一个Map

  • 默认开启,且仅在方法内有效
  • 以SqlSession为例,从创建到用完关闭这段时间,就是一级缓存发挥作用的时候
  • 在一个Session中查询两次相同记录得到的对象相同
    • 走了一级缓存
    • 如果中间存在insert, update, delete等操作,commit后会刷新缓存
    • 此时,查询两次相同记录得到的对象不同

对象不同

public static void main(String[] args) {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user1 = mapper.getUserByID(1);
  
    User newUser = new User(4, "李五", "1235");
    mapper.updateUser(newUser);
    sqlSession.commit();
  
    User user2 = mapper.getUserByID(1);
    System.out.println(user1 == user2);
    sqlSession.close();
}

对象相同

public static void main(String[] args) {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  
    User user1 = mapper.getUserByID(1);
    User user2 = mapper.getUserByID(1);
  
    System.out.println(user1 == user2);
    sqlSession.close();
}

二级缓存

作用域为一个Mapper,即namespace

  • 在全局配置中添加setting
<settings>
    <setting name="logImpl" value="STDOUT_LOGGING"/>
    <setting name="cacheEnabled" value="true"/>
</settings>
  • cache后面的属性可加可不加
<mapper namespace="com.lu.dao.UserMapper">
    <cache eviction="FIFO"
            flushInterval="60000"
            size="512"
            readOnly="true"/>

    <select id="getUserByID" parameterType="int" resultType="user">
        select * from mybatis.user where id = #{uid}
    </select>
</mapper>
  • 当一级缓存失效(SqlSession关闭),二级缓存才开始起作用
public static void main(String[] args) {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    SqlSession session = MyBatisUtil.getSqlSession();

    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user1 = mapper.getUserByID(1);
    sqlSession.close();

    UserMapper sessionMapper = session.getMapper(UserMapper.class);
    User user2 = sessionMapper.getUserByID(1);
    session.close();
    System.out.println(user1 == user2);
}

缓存顺序

查看

  1. 用户首先查看二级缓存中有没有
  2. 再看一级缓存有没有
  3. 最后在数据库查询

生成

  1. 从数据库查询到信息
  2. 保存在SqlSession中(一级缓存)
  3. SqlSession关闭后,上提到二级缓存

Ehcache

浅尝辄止,知道有这个东西就行了,就不记录了

posted @ 2023-05-18 21:04  James-Allen  阅读(22)  评论(0)    收藏  举报