010-Mybatis


2.第一个mybatis程序

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

2.1、搭建环境

搭建数据库

CREATE DATABASE mybatis;

USE mybatis;

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

INSERT INTO `user` VALUES(1,'lwj','dasd'),
(2,'231','321');

新建项目

  1. 新建一个普通maven项目
  2. 删除src目录
  3. 导入maven依赖
<!--导入依赖-->
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.9</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
          </dependencies>

2.2、创建一个模块

  • 编写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>
    <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?userSSL=true&amp;userUnicode=true"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
</configuration>
  • 编写mybatis的工具类
private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            //获取sqlSessionFactory对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
             sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }

2.3、编写代码

  • 实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    int user;
    String name;
    String pwd;
}
  • Dao接口
public interface UserDao {
    List<User> getuserlist();
}
  • 接口实现类由原来的UserDaoImpl转变为一个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">
<mapper namespace="com.lwj.dao.UserDao">
    <select id="getuserlist" resultType="com.lwj.pojo.User">
        select * from user
    </select>
</mapper> 

2.4 测试

注意点:

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

MapperRegistry

  • junit测试

3.CRUD

1、namespace

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

2、select

选择,查询语句

  • id:就是对应的namespace中的方法名
  • resultType:Sql语句执行的返回值!
  • paramaterType:参数类型!

1.编写接口

//根据id查询用户
   User getUser(int id);

2.编写对应的mapper中的SQL语句

<select id="getUser" parameterType="int" resultType="com.lwj.pojo.User">
        select * from user where id = #{id};
    </select>

3.测试

@Test
   public void getUser(){
       SqlSession sqlSession = MybatisUtils.getSqlSession();
       UserMapper mapper = sqlSession.getMapper(UserMapper.class);
       User user = mapper.getUser(1);
       System.out.println(user);
       sqlSession.close();
   }

3、insert

<insert id="insertUser" parameterType="com.lwj.pojo.User">
        insert into user(id, name, pwd) values (#{id} ,#{name}, #{pwd})
    </insert>

4、update

<update id="changeUser" parameterType="com.lwj.pojo.User" >
        update user set name = #{name}, pwd = #{pwd} where id = #{id}
    </update>

5、delete

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

注意点:

  • 增删改需要提交事务!

6、Map

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

int addUer(Map<String,Object> map);
<insert id="addUser" parameterType="map" >
        insert into user(id, name, pwd) values (#{userid} ,#{username}, #{userpwd})
    </insert>
public void addUser(){
       SqlSession sqlSession = MybatisUtils.getSqlSession();
       UserMapper mapper = sqlSession.getMapper(UserMapper.class);
       Map<String, Object> map = new HashMap<>();
       map.put("userid",123);
       map.put("username","ddd");
       map.put("userpwd","123143");
       int i = mapper.addUer(map);
       sqlSession.close();
   }

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

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

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

多个参数用map,或者注解、

8、模糊查询

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

List<User> l = mapper.getUserlike("%你%");

2.在sql拼接中使用通配符!

select * from user where name like "%"{name}"%"
select * from user where name like concat('%', #{name},'%' )

4、配置解析

1、核心配置文件

  • mybatis-comfig.xml
  • Mybatis的配置文件包含了会深深影响Mybatis行为的设置和属性信息

2、环境变量

mybatis可以适应多种环境

不过要记住:尽管可以配置多个环境,但每个sqlsessionFactory实例只能选择一种环境。

学会使用配置多套运行环境!

Mybatis默认的事务管理器就是jdbc,连接池:POOLED

3、属性(properties)

我们可以通过properties属性来实现引用配置文件

这些属性都是可外部配置且可动态替换的,既可以在典型的java属性文件中配置,亦可通过properties元素的子元素来传递。【db.properties】

编写一个配置文件

image-20220410212911662

db.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?userSSL=true&userUnicode=true&characterEncoding=UTF-8
username=root
password=123456

在核心配置文件中引入

<!--    引入外部配置文件-->
    <properties resource="db.properties"/>
  • 可以直接引入外部文件
  • 可以在其中增加一些属性配置
  • 如果两个文件有同一个字段,优先使用外部配置文件的!

4、类型别名(typeAliases)

  • 类型别名是为java类型设置一个短的的名字
  • 存在的意义仅在与用来减少类完全限定名的冗余
<typeAliases>
        <typeAlias  alias="User" type="com.lwj.pojo.User" />
    </typeAliases>

也可以指定一个包名,mybatis会在包名下面搜索需要的javabean,比如:

扫描实体类的包,它的默认别名就为这个类的类名,首字母小写!

<typeAliases>
        <package name="com.lwj.pojo"/>
    </typeAliases>

在实体类比较少的时候,使用第一种方式。可以自定义别名

如果实体类十分多,建议使用第二种。

如果需要改别名,在实体类上增加注解

@Alias("user")
public class User {}

5、设置

这是mybatis中极为重要的调整设置,它们会改变mybatis的运行时行为

6、其他配置

  • typeHandlers(类对象处理器)
  • objectFactory(对象工厂)
  • plaugins插件

7、映射器(mappers)

mapperRegistry:注册绑定我们的Mapper文件

1.推荐

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

2.使用class文件绑定注册

<mappers>
        <mapper class="com.lwj.dao.UserDao"/>
    </mappers>

注意点:

  • 接口和mapper配置文件必须同名
  • 接口和mapper配置文件必须在同一包下

3.使用扫描包进行注入绑定

<mappers>
       <package name="com.lwj.dao"/>
   </mappers>

注意点:

  • 接口和mapper配置文件必须同名
  • 接口和mapper配置文件必须在同一包下

8、生命周期

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

SQLSessionFactoryBuilder:

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

SqlSessionFactory:

  • 就是可以为:数据库连接池
  • SqlSessionFactory一旦被创建
  • 因此sqlsessionfactory的最佳作用域时应用作用域
  • 最简单的就是使用单例模式或者静态单例模式

SqlSeeion

  • 连接到连接池的一个请求
  • sqlsession的实例不是线程安全的,因此是不能被共享的,所以它的最佳作用域是请求或方法作用域
  • 用完关闭,否则资源被占用

sqlsession可以获得多个mapper

mapper代表具体的业务

5、解决属性名和字段名不一致的问题

ResultMapper

数据库中二点字段

image-20220413210923567

新建一个项目,拷贝之前,测试实体类字段不一致的情况

public class User {
    int user;
    String name;
    String password;
}

测试出现问题

password = null

解决方法:

  • 起别名
<select id="getuserlist" resultType="com.lwj.pojo.User">
        select id,name,pwd as password from user;
    </select>

2、resultMap

结果集映射

id name pwd
id name password     
<!--    结果集映射-->
    <resultMap id="userMap" type="User">
<!--        column数据库中的字段,property实体类中的属性-->
        <result column="id" property="user"/>
        <result column="name" property="name"/>
        <result column="pwd" property="password"/>
    </resultMap>
 <!--    只要设置不一致就行-->   
    
  • resultMap元素是Mybatis中最重要最强大点元素
  • ResultMap的设计思想就是,对于简单的语句根本不需要配置显式的结果映射,而面对复杂一点的语句只需要描述它们关系就行了。
  • ResultMap最优秀的地方在与,虽然你已经对它相当的了解了,但是根本就不需要显式地用到他们。

6、日志

6.1、日志工厂

如果一个数据库操作,出现异常,我们需要排错,日志

sout、debug

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

Screenshot_20220418_215709

在Mybatis中具体只用哪一个日志实现,在设置中设定!

STDOUT_LOGGING标准日志输出

6.2、Log4j

  1. 先导入log4j的包

    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
  2. log4j.properties

#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
   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/logFile.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
  1. 配置log4j为日志实现

    <settings>
    	<setting name="logImpl" value="LOG4J"/>
    </settings>
  2. log4j的使用

image-20220418222124267

简单实用

  1. 在要使用Log4j的类中,导入包import org.apache.log4j.Logger;
  2. 日志对象,参数为当前类的class
  3. 日志级别
log.info("进入了info方法");
log.debug("进入了debug方法");
log.error("进入了error方法");

7、分页

  • 减少数据的处理量

使用limit分页

语法:SELECT * from `user` LIMIT 0[startindex],2[pageSize]
SELECT * from `user` LIMIT 3;#[0,n]

使用mybatis实现分页,核心sql

  1. 接口

    //分页
    List<User> userListLimit = mapper.getUserListLimit(map);
  2. mapper.xml

    <!-- 分页-->
        <select id="getUserListLimit" resultType="com.lwj.pojo.User" parameterType="map">
            select id,name,pwd  from user limit ${startIndex}, ${pageSize};
        </select>
  3. 测试

    @Test
       public void getUserListLimit(){
           Map<String, Integer> map = new HashMap<>();
           map.put("startIndex",1);
           map.put("pageSize",2);
           SqlSession sqlSession = MybatisUtils.getSqlSession();
           UserDao mapper = sqlSession.getMapper(UserDao.class);
           List<User> userListLimit = mapper.getUserListLimit(map);
           for (User user: userListLimit) {
               log.info(user);
           }
           sqlSession.close();
       }

8、使用注解开发

8.1、使用注解开发

1.注解在接口上实现

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

2.需要在核心配置文件中绑定接口

<!--绑定接口-->
    <mappers>
        <mapper class="com.lwj.dao.UserDao"/>
    </mappers>
  3. 测试

本质:反射机制实现

底层:动态代理!

Screenshot_20220420_163442

mybatis详细的执行流程

8.2、CRUD

我们可以在工具类创建的时候事项自动提交事务!

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

编写接口,增加注解

User getUserById();

List<User> getUserListLimit(Map<String, Integer> map);

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

@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);

测试类

注意:我们必须要将接口注册绑定到核心配置文件中

@Test
    public void getUserList(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //底层主要应用反射
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        /* List<User> userList = mapper.getUserList();
            for (User user:userList){
            log.info(""+user);
        }*/

        User userByID = mapper.getUserById(1);
        log.info(userByID.toString());

        /*User user = new User(3,"lwj","123456");
        int i = mapper.updateUser(user);*/
        int i = mapper.deleteUser(1);
//        int i = mapper.addUser(user);
        log.info(i+"");
        sqlSession.close();
    }

关于@param()注解

  • 基本类型参数或者String类型,需要加上
  • 引用类型不需要加
  • 如果只有一个基本类型,可以忽略,建议加上
  • 在sql中引用的就是我们这里的@param(“uid”)中设定的属性名!

#{} ${}区别

https://blog.csdn.net/weixin_41231928/article/details/105120292

9、lomobk

  • java library

  • plugs

  • build tools

  • annotation

使用步骤:

新版idea已经将lombok插件内置其中

使用maven导入Lombok jar包

@Date 
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@ToString

10、多对一处理

环境搭建测试

  1. 导入Lombok

  2. 新建实体类Teacher, student

  3. 建立mapper接口

  4. 建立Mapper.xml文件

  5. 在核心配置文件中绑定我们的Mapper接口或文件

  6. 测试查询是否能够成功

按照查询嵌套处理

<!--
思路:
    1.查询所有的学生信息
    2.根据查询出来的学生的tid,寻找对应的老师! 子查询


-->

    <resultMap id="StudentTeacher" type="com.lwj.pojo.Student">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
<!--复杂的属性,我们需要单独处理 对象:association 集合:collection-->
        <association property="user" column="uid" javaType="User" select="getTeacher"/>
    </resultMap>
    <select id="getStudent" resultMap="StudentTeacher">
        select * from student
    </select>

    <select id="getTeacher" resultType="com.lwj.pojo.User">
        select * from user where id = #{id}
    </select>

按照结果嵌套处理

<!--    ===================================================================  -->
<!-- 按照结果嵌套处理 -->
<!--
    1.查询所有的学生信息
    2.根据查询出来的学生的tid,寻找对应的老师!
-->
<select id="getStudent2" resultMap="StudentTeacher2">
    select s.id sid,s.name sname,u.name tname,u.pwd,u.id from student s , user u where s.uid = u.id;
</select>
<resultMap id="StudentTeacher2" type="com.lwj.pojo.Student">
    <result property="id" column="sid"/>
    <result property="name" column="sname"/>
    <association property="user" javaType="User">
        <result property="name" column="tname"/>
        <result property="pwd" column="pwd"/>
        <result property="id" column="id"/>
    </association>
</resultMap>

mysql多对一查询方式:

  • 子查询
  • 联表查询

11、一对多处理

比如:一个老师拥有多个学生!

对于老师而言,就是一对多的关系!

1、环境搭建,和刚才的一样

实体类

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

    private int tid;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    int id;
    String name;
    String pwd;

    //一个老师拥有多个学生
    private List<Student> students;
}

按照结果嵌套处理

<!--    按结果嵌套查询-->
    <select id="getUserById" resultMap="TeacherStudent">
        select  s.id sid , s.name sname ,t.name tname, t.id tid
        from student s,user t
        where s.id = t.id and t.id = #{id}
    </select>

    <resultMap id="TeacherStudent" type="Teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
<!--        复杂的属性,我们需要单独处理 对象assoction 集合 collection
            javatype="" 指定属性的类型!
            集合中的泛型信息,我们使用oftype获取
-->
        <collection property="students" ofType="Student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>

按照查询嵌套处理

<select id="getTeacher2" resultMap="TeacherStudent2">
    select * from user where id = #{id}
</select>
<resultMap id="TeacherStudent2" type="Teacher">
    <result property="id" column="id"/>
    <result property="name" column="name"/>
    <result property="pwd" column="pwd"/>
    <collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId" column="id"/>
</resultMap>
<select id="getStudentByTeacherId" resultType="Student">
    select *
    from student
    where id = #{id};
</select>

小结

  1. 关联-assoction
  2. 集合-collection
  3. javatype & of type
    1. javatype 用来指定实体类属性的类型
             2. oftype 用来指定映射到list或者集合中的pojo类型,泛型中的约束类型
    

注意点:

  • 保证sql的可读性,尽量通俗易懂
  • 注意一对多和多对一中,属性名和字段的问题
  • 如果要排查问题,使用日志。

12、动态sql

动态sql,就是根据不同的条件生成不同的sql语句

使用动态sql特性

如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

搭建环境

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;

创建一个基础工程

  1. 导包
  2. 编写配置文件
  3. 编写实体类
@Data
public class Blog {
    private int id;
    private String title;
    private String author;
    private Date createTime;
    private int views;
}
  1. 编写实体类对应Mapper接口和mapper.xml文件

IF

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

choose (when, otherwise)

<select id="queryBlogChoose" parameterType="Map" resultType="blog">
    select *
    from blog
    <where>
    <choose>
        <when test="title != null">
             title = #{title}
        </when>
        <when test="author != null">
            and author = #{author}
        </when>
        <otherwise>
            and views = #{views}
        </otherwise>
    </choose>
    </where>
</select>

trim (where, set)

<select id="queryBlogIF" parameterType="Map" resultType="blog">
    select *
    from blog
    <where>
    <if test="title != null">
         title = #{title}
    </if>
    <if test="author != null">
        and author = #{author}
    </if>
    </where>
</select>
<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>

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

if

where,set,choose,when

sql片段

有时,将一些功能的部分抽取出来,方便复用!

  1. 使用sql标签抽取公共部分
<sql id="if-title-author">
    <if test="title != null">
        title = #{title},
    </if>
    <if test="author != null">
        author = #{author}
    </if>
</sql>
  1. 在需要的使用的地方使用include标签引用即可
<update id="updateBlog" parameterType="Map">
    update blog
        <set>
            <include refid="if-title-author"></include>
        </set>
    where id = #{id}
</update>

注意事项:

  • 最好基于单表来定义sql标签
  • 不要存在where,set等标签

Foreach

select * from user where 1=1 and 
<foreach item="id" index="index" collection="ids"
         open="(" separtor="or" close=")">
		#{id}
</foreach>

(id=1 or id=2 or id=3)
<!-- 传递map,map中可以存在一个集合 map中的key的名ids是个列表-->
    <select id="queryBlogForeach" parameterType="Map" resultType="blog">
        select *
        from blog
        <where>
            <foreach collection="ids" item="id" open="and (" close=")" separator="or">
                id = #{id}
            </foreach>
        </where>
    </select>

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

建议在mysql中写出sql语句,在修改为对应的动态sql语句

13、缓存

13.1、简介

查询:连接数据库,耗资源!
	一次查询的结果,给他暂存在一个可以直接取到的地方!-->内存:缓存

再次查匈奴相同的数据时候,直接走缓存,就不用走数据库了
  1. 什么是缓存?

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

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

    • 经常查询并且不经常改变的数据。

13.2、mybatis缓存

  • mybatis包含一个非常强大的查询缓存特性,它可以非常方便的定制和配置缓存。缓存可以极大的提升查询效率。
  • mybatis系统中默认定义了两级缓存:一级缓存和二级缓存
    • 默认情况下,只有一级缓存开启。(sqlsession级别的缓存,也称为本地缓存)
    • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
    • 为了提高扩展性,mybatis定义了缓存接口cache。我们可以通过实现cache接口来自定义二级缓存。

13.3、一级缓存

  • 一级缓存也叫本地缓存:SQL session
    • 与数据库同一次会话期间查询到的数据会放在本地数据缓存中
    • 以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库

测试步骤:

  • 开启日志
  • 测试在一个sesion中查询两次相同的记录
  • 查看日志输出

缓存失效情况

  1. 查询不同的东西

  2. 增删改操作,可能会改变原来的数据,所以必定会刷新缓存!

  3. 查询不同的mapper.xml

  4. 手动清理缓存

小结:一级缓存默认是开启的,只在一次sqlsession中有效,也就是拿到连接到关闭连接这个区间段!

一级缓存相当于一个map。

13.4、二级缓存

  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
  • 基于namespace级别的缓存,一个名称控件,对应一个二级缓存;
  • 工作机制
    • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
    • 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中
    • 新的会话查询信息,就可以从二级缓存中获取内容
    • 不同的mapper查出的数据会放在自己对应的缓存(map)中

步骤:

  1. 开启全局缓存
<!--        显示的开启全局缓存 ,默认开启-->
        <setting name="cacheEnabled" value="true"/>
  1. 在要使用二级缓存的mapper中开启
<!--    在当前mapper.xml中使用二级缓存-->
<cache/>
<!--    也可以自定义参数-->
<cache  eviction="FIFO"
            flushInterval="60000"
            size="512"
            readOnly="true"
    />
  1. 测试
    1. 问题:我们需要将实体类进行序列化!否则会报错
    2. 所有的数据都会放在一级缓存中!
    3. 只有当会话提交,或者关闭的时候,才会提交到二级缓存中!

13.5、缓存原理

13.6、自定义缓存-ehcache

Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。

要在程序中使用ehcache,先要导包!

org.mybatis.caches mybatis-ehcache 1.2.1

在mapper中指定使用我们的ehcache缓存实现!

<!--    在当前mapper.xml中使用二级缓存-->
    <cache  type="org.mybatis.caches.ehcache.EhBlockingCache"
    />

redis数据库来做缓存! k-v键值对


文章作者: 半页
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 半页 !
评论
  目录