0%

Mybatis_笔记(狂神)

狂神Mybatis教学视频学习笔记,仅实操重要部分,面向秋招学习,知识点

  • mybaits实现的两种方式:xml文件和注解
  • 映射器(mappers)实现的三种方式
  • 参数的map映射、结果集的map映射
  • 分页、动态SQL、mybatis的两级缓存的机制

Mybatis_狂神笔记

环境:JDK11.0.6、Mysql 5.7、maven 3.3.9、IDEA

1、简介

1.1、什么是Mybatis

1569633932712

  • MyBatis 是一款优秀的持久层框架
  • 它支持定制化 SQL、存储过程以及高级映射。
  • MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
  • MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
  • MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。
  • 2013年11月迁移到Github。

如何获得Mybatis?

1.2、持久化

数据持久化

  • 持久化就是将程序的数据在持久状态和瞬时状态转化的过程
  • 内存:断电即失
  • 数据库(Jdbc),io文件持久化。
  • 生活:冷藏. 罐头。

为什么需要需要持久化?

  • 有一些对象,不能让他丢掉。

  • 内存太贵了

1.3、持久层

Dao层,Service层,Controller层….

  • 完成持久化工作的代码块
  • 层界限十分明显。

1.4 为什么需要Mybatis?

  • 帮助程序猿将数据存入到数据库中。
  • 方便
  • 传统的JDBC代码太复杂了。简化。框架。自动化。
  • 不用Mybatis也可以。更容易上手。 技术没有高低之分
  • 优点:
    • 简单易学
    • 灵活
    • sql和代码的分离,提高了可维护性。
    • 提供映射标签,支持对象与数据库的orm字段关系映射
    • 提供对象关系映射标签,支持对象关系组建维护
    • 提供xml标签,支持编写动态sql。(动态sql是什么意思)

最重要的一点:使用的人多!

Spring SpringMVC SpringBoot

2、第一个Mybatis程序

思路:搭建环境–>导入Mybatis–>编写代码–>测试!

2.1、搭建环境

搭建数据库:打开SQLyog建表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CREATE DATABASE `mybatis`;

USE `mybatis`;

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

INSERT INTO `user`(`id`,`name`,`pwd`) VALUES
(1,'狂神','123456'),
(2,'张三','123456'),
(3,'李四','123890')

新建项目

  1. 新建一个普通的maven项目(父项目)

  2. 删除src目录

  3. 导入maven依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <!--导入依赖-->
    <dependencies>
    <!--mysql驱动-->
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
    </dependency>
    <!--mybatis-->
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.2</version>
    </dependency>
    <!--junit-->
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    </dependency>
    </dependencies>

2.2、创建一个模块(子项目)

  • 编写mybatis的核心配置文件:resources下建一个mybaits-config.xml文件

  • 连接数据库

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <?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.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
    <property name="username" value="root"/>
    <property name="password" value="526736"/>
    </dataSource>
    </environment>
    </environments>

    </configuration>
  • 为了从 XML 中构建 SqlSessionFactory类,,编写mybatis工具类

    在Utils包下建MybatisUtils类:

    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
    //sqlSessionFactory --> sqlSession
    public class MybatisUtils {
    //提升作用域
    private static SqlSessionFactory sqlSessionFactory;

    static{
    try {
    //使用Mybatis第一步:获取sqlSessionFactory对象
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    } catch (IOException e) {
    e.printStackTrace();
    }

    }

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

    }

2.3、编写代码

  • pojo包下写User实体类

    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
    44
    45
    46
    47
    48
    49
    50
    51
    package com.kuang.pojo;

    //实体类
    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接口

    1
    2
    3
    public interface UserDao {
    List<User> getUserList();
    }

    以前的方法的话就要再写一个UserDao的实现类,用来配置和数据库的连接,现在用来mybaits之后就不需要了,用一个UserMapper.xml的配置文件代替就好了。(这里先暂时建在dao包下面)

  • 接口实现类由原来的UserDaoImpl转变为一个 Mapper.xml配置文件.

    namespace=绑定一个对应的Dao/Mapper接口;id就是抽象的方法名,相当于重写了那个抽象方法、这么理解。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <?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=绑定一个对应的Dao/Mapper接口-->
    <mapper namespace="com.kuang.dao.UserDao">

    <!--select查询语句-->
    <select id="getUserList" resultType="com.kuang.pojo.User">
    select * from mybatis.user
    </select>

    </mapper>

2.4、测试

出现异常:(绑定异常!!)

org.apache.ibatis.binding.BindingException: Type interface com.kuang.dao.UserDao is not known to the MapperRegistry.

MapperRegistry是什么?

核心配置文件中注册 mappers:

1
2
3
4
<mappers>
<!-- 每一个mapper.xml都需要再mybatis核心配置文件中注册-->
<mapper resource="com/kuang/dao/UserMapper.xml"/>
</mappers>

如果是因为mapper.xml写在dao包下导致错误,,应该在子父项目的pom.xml里面都加上(如果还不行,就把xml里里面的中文注释给去掉)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!--在build中配置resources,来防止我们资源导出失败的问题-->
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
  • junit测试:再text的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    @Test
    public void test(){
    //第一步:获得SqlSession对象
    SqlSession sqlSession = MybatisUtils.getSqlSession();


    //方式一:getMapper
    //相当于调用dao包下面的UserDao类及其下的方法
    UserDao userDao = sqlSession.getMapper(UserDao.class);
    List<User> userList = userDao.getUserList();

    for (User user : userList) {
    System.out.println(user);
    }

    //关闭SqlSession
    sqlSession.close();
    }

你们可以能会遇到的问题:

  1. 配置文件没有注册
  2. 绑定接口错误。
  3. 方法名不对
  4. 返回类型不对
  5. Maven导出资源问题
image-20210323195446143

3、CRUD(基础)

3.1、namespace

namespace中的包名要和 Dao/mapper 接口的包名一致!

3.2、select

选择,查询语句;

  • id : 就是对应的namespace中的方法名;
  • resultType:Sql语句执行的返回值!
  • parameterType : 参数类型!
  1. 编写接口

    1
    2
    //根据ID查询用户
    User getUserById(int id);
  2. 编写对应的mapper.xml中的sql语句

    1
    2
    3
    4
    <select id="getUserById" parameterType="int" resultType="com.kuang.pojo.User">
    select * from mybatis.user where id = #{id}
    </select>

  3. 测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Test
    public void getUserById() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    User user = mapper.getUserById(1);
    System.out.println(user);

    sqlSession.close();
    }

3.3、Insert

1
2
3
4
<!--对象中的属性,可以直接取出来-->
<insert id="addUser" parameterType="com.kuang.pojo.User">
insert into mybatis.user (id, name, pwd) values (#{id},#{name},#{pwd});
</insert>

3.4、update

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

3.5、Delete

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

注意点:

  • 增删改需要提交事务!,也可以在配置文件中设置增删改自动提交事务

3.6、分析错误

  • 标签不要匹配错
  • resource 绑定mapper,需要使用路径!
  • 程序配置文件必须符合规范!
  • NullPointerException,没有注册到资源!
  • 输出的xml文件中存在中文乱码问题!
  • maven资源没有导出问题!

3.7、万能Map

假设,我们的实体类,或者数据库中的表,字段或者参数过多,我们应当考虑使用Map!

1
2
3
//万能的Map
int addUser2(Map<String,Object> map);

1
2
3
4
<!--对象中的属性,可以直接取出来    传递map的key-->
<insert id="addUser" parameterType="map">
insert into mybatis.user (id, pwd) values (#{userid},#{passWord});
</insert>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
public void addUser2(){
SqlSession sqlSession = MybatisUtils.getSqlSession();

UserMapper mapper = sqlSession.getMapper(UserMapper.class);


Map<String, Object> map = new HashMap<String, Object>();

map.put("userid",5);
map.put("passWord","2222333");

mapper.addUser2(map);

sqlSession.close();
}

Map传递参数,直接在sql中取出key即可! 【parameterType=”map”】

对象传递参数,直接在sql中取对象的属性即可!【parameterType=”Object”】

只有一个基本类型参数的情况下,可以直接在sql中取到!

多个参数用Map,或者注解!

3.8、思考题

模糊查询怎么写?

  1. Java代码执行的时候,传递通配符 % %

    1
    List<User> userList = mapper.getUserLike("%李%");
  2. 在sql拼接中使用通配符!

    1
    select * from mybatis.user where name like "%"#{value}"%"

3.9、结果集映射resultMap

1
2
id   name   pwd
id name password

在UserMapper.xml中单独写一个结果集的映射,就是返回的结果是一个map

1
2
3
4
5
6
7
8
9
10
11
<!--结果集映射-->
<resultMap id="UserMap" type="User">
<!--column数据库中的字段,property实体类中的属性-->
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>

<select id="getUserById" resultMap="UserMap">
select * from mybatis.user where id = #{id}
</select>
  • resultMap 元素是 MyBatis 中最重要最强大的元素
  • ResultMap 的设计思想是,对于简单的语句根本不需要配置显式的结果映射,而对于复杂一点的语句只需要描述它们的关系就行了。
  • ResultMap 最优秀的地方在于,虽然你已经对它相当了解了,但是根本就不需要显式地用到他们。
  • 如果世界总是这么简单就好了。

4、配置解析

就是mybatis的核心配置文件:mybaits-config.xml

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
<?xml version="1.0" encoding="UTF8" ?>
<!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.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="526736"/>
</dataSource>
</environment>
</environments>


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

</configuration>

配置名

1
2
3
4
5
6
7
8
9
10
11
12
13
configuration(配置)
properties(属性):可以直接写,也可以调用外部的db.properties属性配置文件
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件):如mybatis-plus
environments(环境配置)
environment(环境变量):每个 SqlSessionFactory 实例只能选择一种环境
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器):'每一个Mapper.XML都需要在Mybatis核心配置文件中注册!!!' 有三种方式

映射器(mappers)

MapperRegistry:注册绑定我们的Mapper文件;

方式一: 【我目前使用的这种,用来绑定mapper.xml文件,有路径 文件可以放在任意地方】

1
2
3
4
<!--每一个Mapper.XML都需要在Mybatis核心配置文件中注册!-->
<mappers>
<mapper resource="com/kuang/dao/UserMapper.xml"/>
</mappers>

方式二:使用class文件绑定注册【文件需放在resources中,似乎更方便】

1
2
3
4
<!--每一个Mapper.XML都需要在Mybatis核心配置文件中注册!-->
<mappers>
<mapper class="com.kuang.dao.UserMapper"/>
</mappers>

注意点:

  • 接口和他的Mapper配置文件必须同名!
  • 接口和他的Mapper配置文件必须在同一个包下!

方式三:使用扫描包进行注入绑定

1
2
3
4
<!--每一个Mapper.XML都需要在Mybatis核心配置文件中注册!-->
<mappers>
<package name="com.kuang.dao"/>
</mappers>

注意点:

  • 接口和他的Mapper配置文件必须同名!
  • 接口和他的Mapper配置文件必须在同一个包下!

5、生命周期和作用域

这里指的是SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession的作用域

1569660737088

SqlSessionFactoryBuilder:

  • 一旦创建了 SqlSessionFactory,就不再需要它了
  • 局部变量

SqlSessionFactory:

  • 类似数据库连接池

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

  • 因此 SqlSessionFactory 的最佳作用域是应用作用域。 最简单的仅创建一个SqlSessionFactory 的单例

SqlSession

  • 连接到连接池的一个请求!
  • SqlSession 的实例的最佳的作用域是请求或方法作用域。
  • 用完之后需要赶紧关闭,否则资源被占用!

6、分页

有三种实现方式:sql、java对象、分页插件

1、在sql语句层实现,使用Limit分页

  • 接口
1
2
//分页
List<User> getUserByLimit(Map<String,Integer> map);
  • Mapper.xml
1
2
3
4
<!--//分页-->
<select id="getUserByLimit" parameterType="map" resultMap="UserMap">
select * from mybatis.user limit #{startIndex},#{pageSize};
</select>
  • 测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Test
public void getUserByLimit(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);

HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("startIndex",1);
map.put("pageSize",2);

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

2、在java代码层实现,使用RowBounds类分页

是面向对象的思路,但是没有sql快,不学不学

  1. 接口

    1
    2
    //分页2
    List<User> getUserByRowBounds();
  2. mapper.xml

    1
    2
    3
    4
    <!--分页2-->
    <select id="getUserByRowBounds" resultMap="UserMap">
    select * from mybatis.user
    </select>
  3. 测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    @Test
    public void getUserByRowBounds(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    //RowBounds实现
    RowBounds rowBounds = new RowBounds(1, 2);

    //通过Java代码层面实现分页
    List<User> userList = sqlSession.selectList("com.kuang.dao.UserMapper.getUserByRowBounds",null,rowBounds);

    for (User user : userList) {
    System.out.println(user);
    }

    sqlSession.close();
    }

7、使用注解开发

7.1 注解查询示例

注解就是不在使用mapper.xml来实现接口类,而是用注解的方式来实现

本质:反射机制实现 底层:动态代理!

  1. 注解在接口UserMapper上实现

    1
    2
    @Select("select * from user")
    List<User> getUsers();
  2. 需要再核心配置文件中绑定接口!(删掉原来mapper.xml的绑定)

    1
    2
    3
    4
    <!--绑定接口-->
    <mappers>
    <mapper class="com.kuang.dao.UserMapper"/>
    </mappers>
  3. 测试(与之前一样的)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @Test
    public void test(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<User> users = mapper.getUsers();

    for (User user:users){
    System.out.println(user);
    }

    sqlSession.close();
    }

说白了,底层是反射,使用很方便、只用在接口中的抽象方法前面加一个@Select("select * from user")注解就可以了,但一般只能支持简单的查询。(所以我实习的时候还是用的xml那一套)

7.2 使用注解的CRUD

编写接口,增加注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public interface UserMapper {

@Select("select * from user")
List<User> getUsers();

// 方法存在多个参数,所有的参数前面必须加上 @Param("id")注解
@Select("select * from user where id = #{id}")
User getUserByID(@Param("id") int id);


@Insert("insert into user(id,name,pwd) values (#{id},#{name},#{pwd})")
int addUser(User user);


@Update("update user set name=#{name},pwd=#{pwd} where id = #{id}")
int updateUser(User user);


@Delete("delete from user where id = #{uid}")
int deleteUser(@Param("uid") int id);
}

注意事项

  • 基本类型和String类型建议加上@Param("uid"),如有多个参数必须要加(引用类型不用)
  • @Param() 中设定的属性名一定义要和SQL语句中的参数名一样

7.3 #{} ${} 区别

  • MyBatis 在处理 #{} 时,会将 SQL 中的 #{} 替换为 ?,预编译 SQL,通过set()方法进行参数赋值。使用 #{} 可以有效地防止 SQL 注入。

  • 在处理 ${} 时,会直接把${} 替换为参数值,存在 SQL 注入的风险

  • ${}一般用入传入数据库对象,比如数据库表名;mybaties排序时使用order by 动态参数时需要注意,使用${}而不用#{}; (不太懂)

8 多对一处理、一对多处理

1
2
3
4
**MyBatis实现多对一,一对多有几种方式,怎么操作的?**
有联合查询和嵌套查询。
- 联合查询是几个表联合查询,只查询一次,通过在resultMap里面的association,collection节点配置多对一,一对多的类就可以完成
- 嵌套查询是先查一个表,根据这个表里面的结果的外键id,去再另外一个表里面查询数据,也是通过配置association,collection,但另外一个表的查询通过select节点配置。

小结

  1. 关联 - association 【多对一】
  2. 集合 - collection 【一对多】
  3. javaType & ofType
    1. JavaType 用来指定实体类中属性的类型
    2. ofType 用来指定映射到List或者集合中的 pojo类型,泛型中的约束类型!

9 动态SQL

1
2
3
4
5
**Mybatis动态sql是做什么的?都有哪些动态sql?能简述一下动态sql的执行原理不?**

Mybatis动态sql可以让我们在Xml映射文件内,以标签的形式编写动态sql,完成逻辑判断和动态拼接sql的功能,Mybatis提供了9种动态sql标签trim|where|set|foreach|if|choose|when|otherwise|bind。

其执行原理为,使用OGNL从sql参数对象中计算表达式的值,根据表达式的值动态拼接sql,以此来完成动态sql的功能。

动态SQL:就是指根据不同的条件生成不同的SQL语句

==所谓的动态SQL,本质还是SQL语句 , 只是我们可以在SQL层面,去执行一个逻辑代码==

==动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了==

建议:

  • 现在Mysql中写出完整的SQL,再对应的去修改成为我们的动态SQL实现通用即可!
  • (实习我做的东西基本上都是动态查询,就是sql语句里面有判断条件)

举例:使用foreach执行批量操作

1
2
3
4
5
6
7
8
9
select * from user where 1=1 and 

<foreach item="id" collection="ids"
open="(" separator="or" close=")">
#{id}
</foreach>

(id=1 or id=2 or id=3)

1569979229205

1569979339190

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!--
select * from mybatis.blog where 1=1 and (id=1 or id = 2 or id=3)
我们现在传递一个万能的map , 这map中可以存在一个集合!
-->
<select id="queryBlogForeach" parameterType="map" resultType="blog">
select * from mybatis.blog

<where>
<foreach collection="ids" item="id" open="and (" close=")" separator="or">
id = #{id}
</foreach>
</where>

</select>

10、缓存

10.1、缓存定义

  1. 什么是缓存 [ Cache ]?

    • 存在内存中的临时数据。
    • 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。
  2. 为什么使用缓存?

    • 减少和数据库的交互次数,减少系统开销,提高系统效率。
  3. 什么样的数据能使用缓存?

    • 经常查询并且不经常改变的数据。【可以使用缓存】

10.2、Mybatis缓存

  • MyBatis默认定义了两级缓存:一级缓存二级缓存可自定义的二级缓存

一级缓存:

  • 默认开启一级缓存。SqlSession级别的缓存,存在于一次会话之间

  • 所有 select 语句的结果将会被缓存

  • 执行insert、update 和 delete 语句会刷新缓存

  • 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存(默认)。

二级缓存:

  • 基于namespace级别的缓存,一个命名空间Mapper,对应一个二级缓存;(需要手动打开)
  • 如果当前会话关闭了,这个会话对应的一级缓存就失效了;但是如果我们仍需要这个缓存数据,会话关闭时,我们将一级缓存中的数据被保存到二级缓存中;

步骤:

  1. 在mybatis-config.xml中显示的开启全局缓存

    1
    2
    <!--显示的开启全局缓存-->
    <setting name="cacheEnabled" value="true"/>
  2. 在要使用二级缓存的Mapper中开启,即mapper.xml中:

    1
    2
    <!--在当前Mapper.xml中使用二级缓存-->
    <cache/>

    当然也可以自定义参数

    1
    2
    3
    4
    5
    <!--在当前Mapper.xml中使用二级缓存-->
    <cache eviction="FIFO"
    flushInterval="60000"
    size="512"
    readOnly="true"/>
  3. 测试:需要先序列化User类,User类实现Serializable接口就好了

    问题:我们需要将实体类序列化!否则就会报错!Caused by:java.io.NotSerializableException:com.kuang.pojo.User

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public void getUserById() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    SqlSession sqlSession2 = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    UserMapper mapper2 = sqlSession.getMapper(UserMapper.class);

    User user = mapper.getUserById(3);
    System.out.println(user);
    System.out.println("===============");

    User user2 = mapper2.getUserById(3);
    System.out.println(user2);
    System.out.println(user==user2);

    sqlSession.close();
    sqlSession2.close();
    }

自定义缓存ehcache:(跳过)

Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存。停更很多年了16年…

为了提高扩展性,MyBatis还定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存。

缓存查找原理

  • 查数据时,先看二级缓存中有没有
  • 再看一级缓存中有没有
  • 都没有再查询数据库

1569985541106

Redis数据库来做缓存! K-V键值对

11 总结

  • mybaits实现的两种方式:xml文件和注解
  • 练习两种方式的增删改查
  • 映射器(mappers)实现有三种方式
  • 参数的map映射、结果集的map映射、
  • 分页、动态SQL
  • mybatis的两级缓存的机制
-------------感谢阅读没事常来-------------