Mybatis学习笔记

Mybatis框架

Mybatis 是一个使用java编写的持久层框架。它封装了 JDBC的很多细节 ,使开发者只需要关注 sql 语句,而无需关注注册驱动、创建连接、创建 Statement 等繁杂的过程。

采用了 ORM 思想 实现了结果集的封装

> ORM(Object Relational Mapping)对象关系映射。简单地说,就是把数据库表和实体类及实体类的属性对应起来,让我们可以通过操作实体类来操作数据库表。

注意事项

- 在 Mybatis 中,持久层的操作接口名称和映射文件也叫 Mapper ,所以 UserMapper 和 IUserDao 是一样的

- 映射配置文件的 mapper 标签 namespace 属性的取值必须是 mapper 接口的全限定类名 - 映射配置文件的操作配置,id 属性的取值必须是 mapper 接口的方法名

第三个: mybatis的映射配置文件位置必须和dao接口的包结构相同 第四个: 映射配置文件的mapper标签namespace属性的取值必须是dao接口的全限定类名 第五个: 映射配置文件的操作配置(select),id属性的取值必须是dao接口的方法名

当我们遵从了第三,四,五点之后,我们在开发中就无须再写dao的实现类。

第一步: 读取配置文件 第二步: 创建SqlSessionFactory工厂 第三步: 创建SqlSession 第四步: 创建Dao接口的代理对象 第五步: 执行dao中的方法 第六步: 释放资源

注意事项: 不要忘记在映射配置中告知mybatis要封装到哪个实体类中 配置的方式:指定实体类的全限定类名

mybatis基于注解的入门案例: 把IUserDao.xml移除,在dao接口的方法上使用@Select注解,并且指定SQL语句 同时需要在SqlMapConfig.xml中的mapper配置时,使用class属性指定dao接口的全限定类名。 明确: 我们在实际开发中,都是越简便越好,所以都是采用不写dao实现类的方式。 不管使用XML还是注解配置。

但是Mybatis它是支持写dao实现类的。

``

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static void main(String[] args) throws Exception {
//1.读取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3.使用工厂生产SqlSession对象
SqlSession session = factory.openSession();
//4.使用SqlSession创建Dao接口的代理对象
IUserDao userDao = session.getMapper(IUserDao.class);
//5.使用代理对象执行方法
List<User> users = userDao.findAll();
for (User user: users) {
System.out.println(user);
}
//6.释放资源
session.close();
in.close();
}

解释

  • 1.读配置文件不用虚拟路径和绝对路径(容易出现问题),而用①类加载器读取类路径的配置文件。②使用ServletContext对象的getRealPath()
  • 2.创建工厂mybatis使用了构建者模式
    • 构建者模式:把对象的创建细节隐藏,使使用者直接调用方法即可拿到对象。
  • 3.生产SqlSession使用了工厂模式
    • 优势:解耦,降低类之间的依赖关系
  • 4.创建Dao接口实现了代理模式
    • 优势:不修改源码的基础上对功能增强。

自定义Mybatis分析

mybatis在使用代理dao的方式实现增删改查时做什么事呢? 只有两件事: 第一:创建代理对象 第二:在代理对象中调用selectList

)

添加操作,查询操作(CRUD)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
private IUserDao userDao;
private InputStream in;
private SqlSession session;

@Before//用于在测试方法之前执行 !!!
public void init() throws IOException {
//1.读取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3.使用工厂生产SqlSession对象
session = factory.openSession();
//4.使用SqlSession创建Dao接口的代理对象
userDao = session.getMapper(IUserDao.class);
//5.使用代理对象执行方法
}
//释放资源
@After // 用于在测试方法之后执行
public void destroy() throws IOException {
session.commit(); //提交事务,提交后保存数据才会成功! !!!
session.close();
in.close();

}

@Test //测试方法,可以单独运行方法 !!!
public void testFindAll() {
List<User> users = userDao.findAll(); !!!
for (User user: users) {
System.out.println(user);
}
}
@Test
public void testSave(){
User user = new User();
user.setUsername("张三");
user.setAddress("四川省巴中市");
user.setBirthday(Date.valueOf("2019-10-12"));
user.setId(151);
user.setSex("男");
userDao.SaveUser(user); !!!
}

注意:

  • @Before 在测试方法执行前执行 @After :在测试方法后执行
  • @Test 声明为测试方法,可以单独执行
  • session.commit(); 提交事务,提交后“保存”方法才会生效。
1
2
3
4
5
6
7
<insert id="SaveUser">
<!--添加后返回id值 -->
<selectKey resultType="int" keyColumn="id" keyProperty="id" order="AFTER">
select last_insert_id();
</selectKey>
insert into user(username, birthday, sex, address) values(#{username},#{birthday},#{sex},#{address})
</insert>
  • 选择键值

OGNL表达式(Object Graphic Navigatation Language)对象 图 导航 语言

  • 它是通过对象的取值方法来获取数据,在写法上把get省略了
  • 比如获取用户名称:类中写法:user.getUsername(); OGNL写法:user.username.

使用pojo包装类进行查询

  • 在开发中如果想实现复杂查询 ,查询条件不仅包括用户查询条件,还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用 pojo 包装对象传递输入参数
  • 编写 QueryVo 类来封装查询条件
image-20200226120145494

​ ①QueryVo封装了User

1
2
3
4
5
6
7
8
9
public class QueryVo {
private User user; //封装User
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}

​ ②配置mapper.xml

1
2
3
4
<!--    根据QueryVo查询-->
<select id="findUserByVo" parameterType="com.fyw.domain.QueryVo" resultType="com.fyw.domain.User">
select * from user where username like #{user.username};
</select>

​ 注意:

  • ```mysql parameterType="com.fyw.domain.QueryVo", resultType="com.fyw.domain.User">
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    - #{user.username} 用ognl实现,非username

    ③写测试方法

    ```java
    @Test
    public void testFindByVo(){
    QueryVo vo = new QueryVo();
    User user = new User(); //创建对象
    vo.setUser(user); //QueryVo封装User
    user.setUsername("%王%"); //模糊查询字段
    List<User> users = userDao.findUserByVo(vo); //封装后的方法
    for (User u:users ) {
    System.out.println(u);
    }
    }

解决实体类属性名称和数据库列名不对应的方法(自定义类中:userId;数据库中列名:Id)

第一种方式:起别名
  • 在sql语句中用as 起别名从而实现对应(在mysql层面效率高)

第二种方式:配置resultMap

1
2
3
4
5
6
7
8
9
10
11
12
<!-- 配置 resultMap ,完成实体类与数据库表的映射 -->
<resultMap id="userMap" type="cn.ykf.pojo.User">
<id property="userId" column="id" />
<result property="userName" column="username"/>
<result property="userBirthday" column="birthday"/>
<result property="userAddress" column="address"/>
<result property="userSex" column="sex"/>
</resultMap>
<!-- 配置查询所有用户 -->
<select id="listAllUsers" resultMap="userMap">
SELECT * FROM user
</select>
注意:
  • property:java中的名称 column:mysql中的名称
  • 语句上不用resultType 而用 resultMap

配置文件讲解

properties标签

配置数据库连接的时候,我们可以采用以下几种方式来配置:

  • 第一种,采用全局的内部配置。采用这种方式的话,如果需要配置多个数据库环境,那么像 username、password等属性就可以复用,提高开发效率。
1
2
3
4
5
6
7
<!-- 全局变量 -->
<properties>
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/db_mybatis"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</properties>

​ 注意:properties配置后 dataSource的value需要用${driver}代替!

  • 第二种,使用 resources 属性引入外部配置文件(常用)

    编写配置文件 jdbcConfig.properties。配置文件名没有限制,但是配置文件一定要放在类路径下

1
2
3
4
5
# 键为 jdbc.xxx 可以自行修改
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db_mybatis
jdbc.username=root
jdbc.password=123456
1
<properties resource="jdbcConfig.properties"/>
1
<property name="driver" value="${jdbc.driver}"/>

​ 注意:有前缀jdbc. 设置dataSource时value需要加前缀。

  • 第三种,使用 url 属性引入外部配置文件

该方法的外部文件可以放在任意位置,但是路径写法必须按照 Url 的方式,写起来比较麻烦,推荐第二种方法

1
<properties url="file:///D:/document/IdeaProjects/java_web_ssm/my_mybatis/src/main/resources/jdbcConfig.properties"/>
  • URL:Uniform Resouce LOcator,即统一资源定位符。它可以唯一标识一个资源的位置,由四部分组成:协议、主机、端口、路径
    • 例如:http://localhost:8080/mybatisserver/demo1,其中 http 为协议, localhost 为主机,8080 为端口号,/mybatisserver/demo1 为uri(路径)
  • URI:Uniform Resource Identifier,即统一资源标识符。它是在应用中可以唯一定位一个资源的。

typeAliases 标签

  • 之前在编写映射文件的时候, resultType 这个属性可以写 int、INT 等,就是因为 Mybatis 给这些类型起了别名。Mybatis 内置的别名如表格所示:
别名 映射的类型
_byte byte
_long long
_short short
_int int
_integer int
_double double
_float float
_boolean boolean
string String
byte Byte
long Long
short Short
int Integer
integer Integer
double Double
float Float
boolean Boolean
date Date
decimal BigDecimal
bigdecimal BigDecimal
object Object
map Map
hashmap HashMap
list List
arraylist ArrayList
collection Collection
iterator Iterator

如果我们也想给某个实体类指定别名的时候,就可以采用 typeAliases 标签。

1
2
3
4
5
<!--配置别名-->
<typeAliases>
<typeAlias type="com.fyw.domain.User" alias="user"/>
</typeAliases>
<!-- 其他配置省略... -->

type 是属性指定的实体类全限定类名 alias属性指定别名

  • 当我们有多个实体类需要起别名的时候,那么我们就可以使用 package 标签。
1
2
3
4
<typeAliases>
<!-- 包下所有实体类起别名 -->
<package name="com.fyw.domain"/>
</typeAliases>
  • package 标签指定要配置别名的包,当指定之后,该包下的所有实体类都会注册别名,并且别名就是类名,不再区分大小写
  • package 标签还可以将某个包内的映射器接口实现全部注册为映射器,如下所示
1
2
3
4
<!-- 指定映射文件 -->
<mappers>
<package name="com.fyw.mapper"/>
</mappers>

这样配置后,我们就无需一个一个地配置 Mapper 接口了。不过,这种配置方式的前提是映射配置文件位置必须和dao接口的包结构相同,如图所示

3.动态sql语句

MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。

if标签的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<select id="listUsersByCondition" parameterType="com.fyw.domain.User" resultType="com.fyw.domain.User">
SELECT * FROM user WHERE 1 = 1
<if test="username != null and username != ''">
AND username LIKE CONCAT('%',#{username},'%')
</if>
<if test="sex != null and sex != ''">
AND sex = #{sex}
</if>
<if test="address != null and address != ''">
AND address = #{address}
</if>
<if test="birthday != null">
AND birthday = #{birthday}
</if>
</select>

注意

  • WHERE 1 =1 是防止所有条件都为空时拼接 SQL 语句出错。因为不加上 1 = 1 这个恒等条件的话,如果后面查询条件都没拼接成功,那么 SQL 语句最后会带有一个 WHERE 关键字而没有条件,不符合 SQL 语法。
  • `标签中test` 属性是必须的,表示判断的条件。其中有几点需要注意:
    • 如果 test 有多个条件,那么必须使用 and 进行连接,而不能使用 Java 中的 && 运算符。
    • test 中的参数名称必须与实体类的属性保持一致,也就是和 #{参数符号} 保持一致。
    • 如果判断条件为字符串,那么除了判断是否为 null 外,最好也判断一下是否为空字符串,'' ,防止 SQL语句将其作为条件查询。

WHERE标签

将if语句放在where中,可以不用写where 1=1 ,从而优化语句

  • 标签只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入 `WHERE` 子句。而且,若语句的开头为 `AND` 或 `OR`, 标签也会将它们去除。
  • 就是该标签可以动态添加 WHERE 关键字,并且剔除掉 SQL 语句中多余的 AND 或者 OR

foreach 标签的使用

  • 如果使用普通 SQL 语句的话,那么查询语句应该这样写:SELECT \* FROM user WHERE id IN(41,42,43);
  • 因此,如果想使用动态 SQL 来完成的话,那么我们就应该考虑如何拼接上 id IN(41,42,43) 这一串内容,这时候,我们的 <foreach></foreach> 标签就出场了。

流程:

  • 首先修改 QueryVo 类,增加一个成员变量用于存放 id 集合,并增加其 getter()/setter()

  • 接下来添加接口方法,并配置映射文件

1
2
3
4
5
6
7
8
9
10
<select id="listUsersByIds" parameterType="cn.ykf.pojo.QueryVo" resultType="cn.ykf.pojo.User">
SELECT * FROM user
<where>
<if test="ids != null and ids.size > 0">
<foreach collection="ids" open="AND id IN (" close=")" item="id" separator=",">
#{id}
</foreach>
</if>
</where>
</select>

注意

  • collection : 代表要遍历的集合或数组,这个属性是必须的。如果是遍历数组,那么该值只能为 array
  • open : 代表语句的开始部份。
  • close : 代表语句的结束部份。
  • item : 代表遍历集合时的每个元素,相当于一个临时变量。
  • separator : 代表拼接每个元素之间的分隔符。
  • 注意,SQL 语句中的参数符号 #{id} 应该与 item="id" 保持一致,也就是说,item 属性如果把临时变量声明为 uid的话,那么使用时就必须写成 #{uid}

4.Mybatis 多表查询

建立实体类关系

  • 在Account中生成getUser方法,建立主表和从表关系

    1
    2
    3
    4
    5
    6
    public User getUser(){
    return user;
    };
    public Integer getId() {
    return id;
    }
  • 设置xml映射文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <resultMap id="accountUserMap" type="com.fyw.domain.Account">
    <id property="id" column="aid"></id>
    <result property="uid" column="uid"></result>
    <result property="money" column="money"></result>
    <!-- 一对一关系映射,配置user-->
    <association property="user" column="uid" javaType="com.fyw.domain.User">
    <id property="id" column="aid"></id>
    <result property="username" column="username"></result>
    <result property="address" column="address"></result>
    <result property="sex" column="sex"></result>
    <result property="birthday" column="birthday"></result>
    </association>
    </resultMap>
    • 注意:用于一对一映射的,其中property表示要关联的属性,javaType表示要关联实体类的全限定类名(Account关联User)
    • 因为 SQL 语句中为 account 表的 id 字段起了别名 aid ,所以在定义 resultMap 的时候,记得主字段写 column="aid",而不是 column="id"
  • 然后写sql语句

    1
    2
    3
    <select id="findAll" resultMap="accountUserMap">
    SELECT U.*, a.id AS aid, a.uid, a.money from account a, user u WHERE a.uid = u.id;
    </select>
  • 最后写测试方法

    1
    2
    3
    4
    5
    6
    7
    @Test  //测试方法,可以单独运行方法
    public void testFindAll() {
    List<Account> accounts = accountDao.findAll();
    for (Account account: accounts) {
    System.out.println(account);
    System.out.println(" + " + account.getUser());
    }
  • 结果截图

    image-20200227180158940

4.延迟加载与立即加载

  • 延迟加载
    • 延迟加载就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据,延迟加载也称懒加载。
    • 一对多多对多的表关系中,通常情况下我们都是采用延迟加载。
  • 立即加载
    • 立即加载就是不管是否需要数据,只要一进行查询,就会把相关联的数据一并查询出来
    • 多对一一对一的表关系中,通常情况下我们都是采用立即加载。

4.1 一对一实现延迟加载

1
2
3
4
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
  • 注意,在编写 Mybatis 的配置文件时,文档结构一定不可以随便写,一定要按照官方文档所要求的顺序,比如说:标签不可以写在 下方。具体文档结构见下图: 配置文件文档结构
  • 修改上一篇笔记编写好的账户映射文件 AccountMapper.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<mapper namespace="cn.ykf.mapper.AccountMapper">
<!-- 定义可以封装带有User的Account的 resultMap -->
<resultMap id="AccountWithUserMap" type="cn.ykf.pojo.Account">
<id property="id" column="id"/>
<result property="uid" column="uid"/>
<result property="money" column="money"/>
<!-- 关联 User 对象 -->
<association property="user" javaType="cn.ykf.pojo.User" column="uid" select="cn.ykf.mapper.UserMapper.getUserById"></association>
</resultMap>
<!-- 配置查询所有账户,延迟加载用户信息 -->
<select id="listAllAccounts" resultMap="AccountWithUserMap">
SELECT * FROM account
</select>
</mapper>
  • `标签中的select属性表示我们**要调用的映射语句的 ID**,它会**从column` 属性指定的列中检索数据,作为参数传递给目标 select 语句**。
  • column 属性指定传递给我们要调用的映射语句的参数

缓存

  • 什么是缓存?存在内存中的数据
  • 为什么使用缓存?减少和数据库的交互次数,提高执行效率
  • 什么样的数据使用缓存? 经常查询且不常改变的;数据的正确与否对结果影响不大的

一级缓存

  • 一级缓存是 SqlSession 级别的缓存,只要 SqlSession 没有 flushclose,它就会存在。当调用 SqlSession 的修改、添加、删除、commit()、close()、clearCache() 等方法时,就会清空一级缓存。SqlSession不存在缓存也就不存在了。

一级缓存流程如下图 一级缓存分析

  • 第一次发起查询用户 id 为 1 的用户信息,Mybatis 会先去找缓存中是否有 id 为 1 的用户信息,如果没有,从数据库查询用户信息。
  • 得到用户信息,将用户信息存储到一级缓存中
  • 如果 sqlSession 去执行 commit 操作(执行插入、更新、删除),那么 Mybatis 就会清空 SqlSession 中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读
  • 第二次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,缓存中有,直接从缓存中获取用户信息。
  • Mybatis 默认就是使用一次缓存的,不需要配置。
  • 一级缓存中存放的是对象。(一级缓存其实就是 Map 结构,直接存放对象)

二级缓存

  • 二级缓存是 Mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 SQL 语句,多个SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的

  • 二级缓存流程如下图

  • 二级缓存分析
    • sqlSession1 去查询用户信息的时候,Mybatis 会将查询数据存储到二级缓存中。
    • 如果 sqlSession3 去执行相同 Mapper 映射下的 SQL 语句,并且执行 commit 提交,那么 Mybatis 将会清空该 Mapper 映射下的二级缓存区域的数据。
    • sqlSession2 去查询与 sqlSession1 相同的用户信息,Mybatis 首先会去缓存中找是否存在数据,如果存在直接从缓存中取出数据。
  • 流程

  • 首先在 Mybatis 配置文件中添加配置 (这一步其实可以忽略,因为默认值为 true)

1
2
3
4
<settings>
<!-- 开启缓存 -->
<setting name="cacheEnabled" value="true"/>
</settings>
  • 接着在映射文件中配置
1
2
3
4
<mapper namespace="cn.ykf.mapper.UserMapper">
<!-- 使用缓存 -->
<cache/>
</mapper>
  • 最后在需要使用二级缓存的操作上配置 (针对每次查询都需要最新数据的操作,要设置成 useCache="false",禁用二级缓存)
1
2
3
<select id="listAllUsers" resultMap="UserWithAccountsMap" useCache="true">
SELECT * FROM user
</select>
  • 当我们使用二级缓存的时候,所缓存的类一定要实现 java.io.Serializable 接口,这样才可以使用序列化的方式来保存对象。
  • 由于是序列化保存对象,所以二级缓存中存放的是数据,而不是整个对象。

Mybatis注解开发

  • 在 Mybatis 的注解开发中,常用的注解如下表所示:
注解 作用
@Intsert 实现新增
@Update 实现更新
@Delete 实现删除
@Select 实现查询
@Results 实现结果集封装
@ResultMap 实现引用 @Results 定义的封装
@One 实现一对一结果集封装
@Many 实现一对多结果集封装
@SelectProvider 实现动态 SQL 映射
@CacheNamespace 实现注解二级缓存的使用

注意,如果此时实体类的属性与数据库表列名不一致,那么我们应该使用@Results、@Result、@ResultMap 等注解

1
2
3
4
5
6
7
8
9
		@Select("SELECT * FROM user")
@Results(id = "UserMap",value = {
@Result(id = true,property = "userId",column = "id"),
@Result(property = "userName",column = "username"),
@Result(property = "userBirthday",column = "birthday"),
@Result(property = "userSex",column = "sex"),
@Result(property = "userAddress",column = "address"),
})
List<User> listAllUsers();
  • ``` @Results

    1
    2
    3

    注解用于定义映射结果集,相当于标签

    1
    2
    3
    4
    5
    6

    - 其中,`id` 属性为唯一标识。
    - `value` 属性用于接收 `@Result[]` 注解类型的数组。

    - ```
    @Result

    注解用于定义映射关系,相当于标签

    1
    <id />

    1
    <result />
    • 其中,id 属性指定主键。
    • property 属性指定实体类的属性名,column 属性指定数据库表中对应的列。
  • @ResultMap 注解用于引用 @Results 定义的映射结果集,避免了重复定义映射结果集。

4.3 Mybatis 使用注解实现一对多

1
2
3
4
5
6
7
8
9
10
11
@Select("SELECT * FROM user")
@Results(id = "UserMap", value = {
@Result(id = true, property = "userId", column = "id"),
@Result(property = "userName", column = "username"),
@Result(property = "userBirthday", column = "birthday"),
@Result(property = "userSex", column = "sex"),
@Result(property = "userAddress", column = "address"),
@Result(property = "accounts", column = "id",
many = @Many(select = "cn.ykf.mapper.AccountMapper.getAccountByUid", fetchType = FetchType.LAZY))
})
List<User> listAllUsers();
  • ``` @Many

    1
    2
    3

    注解相当于标签

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    是多表查询的关键,在注解中用来指定子查询返回对象集合

    - 其中,`select` 属性指定用于查询的接口方法,`fetchType` 属性用于指定**立即加载或延迟加载**,分别对应 `FetchType.EAGER` 和 `FetchType.LAZY`

    - 在包含 `@Many` 注解的 `@Result` 中,`column` 属性用于指定将要作为**参数进行查询的数据库**表列。

    ### 4.4 Mybatis 使用注解实现二级缓存

    - 如果使用注解时想开启二级缓存,那么首先应该在 Mybatis 配置文件中开启全局配置

    ```xml
    <settings>
    <!-- 开启缓存 -->
    <setting name="cacheEnabled" value="true"/>
    </settings>

  • 接着在持久层接口中使用注解即可

1
2
3
4
@CacheNamespace(blocking = true)
public interface UserMapper {
// .....
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!