MyBatis 04

1,缓存

MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。缓存可以极大的提升查询的效率。
在 MyBatis 中默认定义了两级缓存:一级和二级缓存:

  • 在默认情况下,只开启了一级缓存,也就是sqlsession级别的缓存
  • 二级缓存需要手动开启和配置,它是基于namespace级别的缓存

1.1,一级缓存

一级缓存也叫本地缓存,作用域默认为 SqlSession。当 Session flush 或 close 后,该 Session 中的所有 Cache 都将被清除。
一级缓存不能关闭,但可以调用 clearCache() 来清空一级缓存。

1.1.1,编写接口

在EmployeeMapper接口中,添加方法:

Employee findEmployeeById(int id);

1.1.2,配置映射

<resultMap id="rm" type="Employee">
    <id property="id" column="id" />
    <result property="name" column="name"/>
    <result property="age" column="age"/>
    <result property="did" column="did"/>
</resultMap>
<select id="findEmployeeById" resultMap="rm">
    select id,name,age,did from tb_employee where id=#{id}
</select>

1.1.3,测试

@Test
public void testFindEmployeeById() {
    SqlSession session = MyBatisUtil.openSession();
    EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
    Employee employee = mapper.findEmployeeById(5);
    System.out.println(employee);

    // 第二次查询
    Employee employee1 = mapper.findEmployeeById(5);
    System.out.println(employee1);

    session.close();
}

执行后输出:

15:40:08.591 main DEBUG findEmployeeById ==> Preparing: select id,name,age,did from
tb_employee where id=?15:40:08.629 main DEBUG findEmployeeById
> Parameters: 5(Integer)
2022-02-26 15:40:08.648 main DEBUG findEmployeeById
<
Total: 1
Employee(id=5, name=刘备, age=20, did=1, depart=null)
Employee(id=5, name=刘备, age=20, did=1, depart=null

从上面的输出看到,查询时只发出一条sql语句,第二次查询时候,并没有再发出sql,而是直接从缓存中获取。当我们在两次查询中调用SqlSession.clearCache() ,会清空一级缓存中的数据:

@Test
    public void testFindEmployeeById() {
        SqlSession session = MyBatisUtil.openSession();
        EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
        Employee employee = mapper.findEmployeeById(5);
        System.out.println(employee);

        // 调用清空Cache方法
        session.clearCache();

        // 第二次查询
        Employee employee1 = mapper.findEmployeeById(5);
        System.out.println(employee1);

        session.close();

这样后输出为:

15:43:45.273 main DEBUG findEmployeeById
> Preparing: select id,name,age,did from tb_employee where id=?
15:43:45.309 main DEBUG findEmployeeById
2022-02-26 15:43:45.323 main DEBUG findEmployeeById
<
Total: 1
Employee(id=5, name=刘备, age=20, did=1, depart=null)
15:43:45.337 main DEBUG findEmployeeById
==> Preparing: select id,name,age,did from tb_employee where id=?
15:43:45.338 main DEBUG findEmployeeById
> Parameters: 5(Integer)
2022-02-26 15:43:45.341 main DEBUG findEmployeeById
<
Total: 1
Employee(id=5, name=刘备, age=20, did=1, depart=null)

1.1.4,会使一级缓存失效的情况

一级缓存在以下四种情况下会失效:

  1. 不同的 SqlSession对应不同的一级缓存
  2. 同一个 SqlSession,但查询条件不同
  3. 同一个 SqlSession,但是两次查询期间执行了任何一次插入|修改|删除操作
  4. 同一个 SqlSession,但是两次查询期间手动清空缓存

1.2,二级缓存

二级缓存是Namespace级别的缓存,它是全局缓存。默认情况下,二级缓存没有开启,需要手动配置。
MyBatis 提供了二级缓存的接口以及实现,缓存实现要求我们的 Java 实体对象需要实现 Serializable 接口。二级缓存在 SqlSession 关闭或提交之后才会生效。
使用步骤:

  1. 在全局配置文件中开启二级缓存
   <settings name="cacheEnabled" value="true"/>
  1. 在需要使用二级缓存的映射文件中使用 cache 标签来配置
   <cache/>
  1. 实体类需要实现 Serializable 接口

1.2.1,开启二级缓存

修改mybatis-config.xml文件,添加:

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

1.2.2,添加实体类

@Data
@Accessors(chain = true)
public class Employee implements Serializable {
    private Integer id;
    private String name;
    private int age;
    private Integer did;
    // 关联部门,它是多对一关系
    private Department depart;
}

1.2.3,修改映射文件

<!-- 使用二级缓存 -->
<cache/>
<!-- 根据ID查询 -->
<resultMap id="rm" type="Employee">
    <id property="id" column="id" />
    <result property="name" column="name"/>
    <result property="age" column="age"/>
    <result property="did" column="did"/>
</resultMap>
<select id="findEmployeeById" resultMap="rm">
    select id,name,age,did from tb_employee where id=#{id}
</select>

1.2.4,测试

@Test
public void testFindEmployeeById() {
    SqlSession session = MyBatisUtil.openSession();
    EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
    Employee employee = mapper.findEmployeeById(5);
    System.out.println(employee);
    session.close();

    SqlSession session1 = MyBatisUtil.openSession();
    EmployeeMapper mapper1 = session1.getMapper(EmployeeMapper.class);
    Employee employee1 = mapper1.findEmployeeById(5);
    System.out.println(employee1);
    session1.close();
}

输出结果:

15:59:35.123 main DEBUG EmployeeMapper Cache Hit Ratio [com.xianopeng.mapper.EmployeeMapper]: 0.0
 15:59:35.322 main DEBUG findEmployeeById ==>  Preparing: select id,name,age,did from tb_employee where id=?
15:59:35.346 main DEBUG findEmployeeById ==> Parameters: 5(Integer)
15:59:35.364 main DEBUG findEmployeeById <==      Total: 1
Employee(id=5, name=刘备, age=20, did=1, depart=null)
15:59:35.396 main WARN  SerialFilterChecker As you are using functionality that deserializes object streams, it is recommended to define the JEP-290 serial filter. Please refer to https://docs.oracle.com/pls/topic/lookup?ctx=javase15&id=GUID-8296D8E8-2B93-4B9A-856E-0A65AF9B8C66
15:59:35.401 main DEBUG EmployeeMapper Cache Hit Ratio [com.xianopeng.mapper.EmployeeMapper]: 0.5
Employee(id=5, name=刘备, age=20, did=1, depart=null)

2,注解

MyBatis3开始支持注解

2.1 环境准备

我们以如下表来进行演示:

create table tb_user
(
    id int auto_increment primary key,
    name     varchar(30)  null,
    account  varchar(20)  not null,
    password varchar(32)  not null,
    avatar   varchar(200) null
);

2.1.1 实体类

User.java

@Data
@Accessors(chain = true)
public class User implements Serializable {
    private Integer id;
    private String name;
    private String account;
    private String password;
    private String avatar;
}

2.1.2 编写接口

UserMapper.java

public interface UserMapper {

    void add(User user);

    void update(User user);

    void delete(Integer id);

    User getById(Integer id);

    List<User> getUsers();

    List<User> getUserByAccount(String account);

}

2.2 insert

对插入数据,我们使用 @insert 注解来实现

@SelectKey(keyColumn="id", keyProperty="id", before = false, resultType = int.class, statement="select last_insert_id()")
@Insert("insert into tb_user(name,account,password,avatar) values(#{name},#{account},#{password},#{avatar})")
void add(User user);

把接口文件添加到 mybatis-config.xml 文件中:

<mappers>
    <mapper resource="DepartmentMapper.xml"/>
    <mapper resource="EmployeeMapper.xml"/>
    <mapper class="com.xianopeng.mapper.UserMapper"/>
</mappers>

编写测试:

@Test
public void testInsert() {
    SqlSession session = MyBatisUtil.openSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    User user = new User().setName("王五")
        .setAccount("wangwu")
        .setPassword("123")
        .setAvatar("aa.jpg");
    mapper.add(user);
    session.commit();
    session.close();
    System.out.println(user);
}

2.3 update

使用 @Update 注解来实现更新的操作。

@Update("update tb_user set name=#{name},password=#{password} where id=#{id}")
void update(User user);

编写测试:

@Test
public void testUpdate() {
    SqlSession session = MyBatisUtil.openSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    User user = new User().setName("赵六")
        .setPassword("123")
        .setId(4);
    mapper.update(user);
    session.commit();
    session.close();
    System.out.println(user);
}

2.4 delete

使用 @Delete 注解来实现

@Delete("delete from tb_user where id=#{id}")
void delete(Integer id);

编写测试:

@Test
public void testDelete() {
    SqlSession session = MyBatisUtil.openSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    int id = 4;
    mapper.delete(id);
    session.commit();
    session.close();
}

2.5 select

使用 @Select 注解来进行查询功能。

2.5.1 单条查询

@Select("select id,name,account,password,avatar from tb_user where id=#{id}")
User getById(Integer id);

编写测试:

@Test
public void testGetById() {
    SqlSession session = MyBatisUtil.openSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    int id = 3;
    User user = mapper.getById(id);
    System.out.println(user);
}

查询多条数据:

@Select("select id,name,account,password,avatar from tb_user")
List<User> getUsers();

编写测试:

@Test
public void testGetUsers() {
    SqlSession session = MyBatisUtil.openSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    List<User> users = mapper.getUsers();
    session.close();
    users.forEach(System.out::println);
}

我们还可以返回 resultMap 类型。

@Results(id = "userResult", value = {
    @Result(property = "id", column = "id", id = true), // 主键
    @Result(property = "name", column = "name"),
    @Result(property = "account", column = "account"),
    @Result(property = "password", column = "password")
})
@Select("select id,name,account,password,avatar from tb_user where account=#{account}")
List<User> getUserByAccount(String account);

编写测试:

@Test
public void testGetUserByAccount() {
    SqlSession session = MyBatisUtil.openSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    List<User> users = mapper.getUserByAccount("zs");
    session.close();
    users.forEach(System.out::println);
}

2.6 script

很多时间,我们在做插入、更新、查询时,会有条件,那么我们希望使用 set、where、trim 这些元素,那么就可以通过 script 元素来使用。

例如,我们实现带条件的修改。

@Update({"<script>" +
    "update tb_user " +
    "<trim prefix='set' suffixOverrides=','>" +
    "<if test='name!=null'>name=#{name},</if>" +
    "<if test='password!=null'>password=#{password},</if>" +
    "<if test='avatar!=null'>avatar=#{avatar},</if>" +
    "</trim>" +
    "where id=#{id}" + 
    "</script>"})
void update(User user);

再次执行更新来验证。

@Test
public void testUpdate() {
    SqlSession session = MyBatisUtil.openSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    User user = new User().setName("王麻子")
        .setPassword("123456")
        .setId(3);
    mapper.update(user);
    session.commit();
    session.close();
    System.out.println(user);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值