Mybatis(4) 查询缓存以及Mybatis 逆向工程

MyBatis(4) ---- 查询缓存

  • 用于减轻数据库压力,提高数据库性能
    TIM截图20190519115543.png
  • 如果缓存中又数据,就不用去数据库取数据

一级缓存(是SqlSession级别的缓存, Mybatis 默认支持一级缓存)

一级缓存的原理 ---- sqlSession 级

TIM截图20190519115946.png

  1. 第一次取查询,先去缓存是否存在这个数据,没有
    就去操作数据库,并将查询结果存放到一级缓存

如果sqlSession 去执行commit 时(插入、更新、删除),会清空sqlSession 中
的一级缓存 ---- 目的:为了让缓存内存在的数据是最新的信息,避免脏数据

  1. 第二次取查询,先去缓存是否存在这个数据,如果
    缓存内存在数据,就直接从缓存内取出数据

  • 一级缓存测试
/*一级缓存测试*/
@Test
public void test() throws Exception {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper dao = sqlSession.getMapper(UserMapper.class);

    User user = new User();
    user.setId(1);
    user.setName("上官铁柱");
    PojoVO pojoVO = new PojoVO();
    pojoVO.setUser(user);

    int i = dao.updateUserById(pojoVO);
    //提交,清除一级缓存,避免脏数据
    sqlSession.commit();
    System.out.println(i);

    //第一次查询 --- 查看是否存在缓存,没有就执行sql 查询
    User user1 = dao.findUserById(pojoVO);
    System.out.println(user1.toString());

    //第二次查询 --- 当出现缓存,直接拿取缓存的数据
    User user2 = dao.findUserById(pojoVO);
    System.out.println(user2.toString());
}

  • 注意:

一级缓存在同一个sqlSession 时有效,当sqlSession 关闭时,所对应的一级缓存也会被清空

二级缓存----跨SqlSession(Mapper 级)

  • 是Mapper级别的缓存 — 多个sqlSession 去查找mapper 的语句

二级缓存的原理

TIM截图20190519204149.png

  • 前提:开启mybatis 的二级缓存
  • 注意:mybatis 二级缓存默认关闭;
  • 多个sqlSession 可以共享一个二级缓存区域;
  • 每一个namespace 的mapper 有一个二级缓存区域
  • commit 会清空该mapper 下的二级缓存

  1. 开启二级缓存
  • 开启mybatis 配置文件的缓存开关(默认值为true)
<settings>
    <setting name="cacheEnabled" value="true"/>
</settings>
  • 开启namespace 二级缓存开关
<!-- 开启该namespace 的二级缓存 -->
<cache />
  • 设置pojo 实现序列化接口(存放二级缓存的位置不一定在内存(硬盘等))
public class User implements Serializable{}
  • 二级缓存测试代码1(没有commit)
@Test
    public void testCache_1() throws Exception {
        SqlSession sqlSession0 = sqlSessionFactory.openSession();
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();


        /*第一次发起请求*/
        UserMapper dao0 = sqlSession0.getMapper(UserMapper.class);
        User user = new User();
        user.setId(1);
        user.setName("上官铁柱");
        PojoVO pojoVO = new PojoVO();
        pojoVO.setUser(user);
        User user_1 = dao0.findUserById(pojoVO);
        System.out.println(user_1);

        /*将sqlSession 的数据写到而二级缓存区域*/
        sqlSession0.close();

        /*再次进行查询,查看二级缓存执行过程*/
        UserMapper dao2 = sqlSession2.getMapper(UserMapper.class);
        User user_2 = dao2.findUserById(pojoVO);
        System.out.println(user_2);
        sqlSession2.close();


    }
  • 调试结果

TIM截图20190519231943.png

  • 二级缓存测试代码1(有commit)
@Test
    public void testCache_1() throws Exception {
        SqlSession sqlSession0 = sqlSessionFactory.openSession();
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();


        /*第一次发起请求*/
        UserMapper dao0 = sqlSession0.getMapper(UserMapper.class);
        User user = new User();
        user.setId(1);
        user.setName("上官铁柱");
        PojoVO pojoVO = new PojoVO();
        pojoVO.setUser(user);
        User user_1 = dao0.findUserById(pojoVO);
        System.out.println(user_1);

        /*将sqlSession 的数据写到而二级缓存区域*/
        sqlSession0.close();

        /*进行更新操作,查看二级缓存数据*/
        UserMapper dao1 = sqlSession1.getMapper(UserMapper.class);
        int i = dao1.updateUserById(pojoVO);
        sqlSession1.commit();
        System.out.println(i);
        sqlSession1.close();


        /*再次进行查询,查看二级缓存执行过程*/
        UserMapper dao2 = sqlSession2.getMapper(UserMapper.class);
        User user_2 = dao2.findUserById(pojoVO);
        System.out.println(user_2);
        sqlSession2.close();


    }
  • 调试结果

TIM截图20190519233059.png

二级缓存参水
  • 禁用二级缓存(变化频率高的sql 设置成禁用缓存)
<select id="findUserById" parameterType="pojoVO" resultType="user" useCache="false">
    SELECT * FROM user
    WHERE id=#{user.id}
</select>
  • 调试结果

TIM截图20190519233823.png


  • 刷新缓存(清空缓存)

一般情况下,commit 操作执行后都需要刷新缓存,避免脏数据

<update id="updateUserById" parameterType="pojoVO" flushCache="true">

Mybatis 整合 ehcache

  • ehcache 是一个分布式缓存

整合方法

  • Mybatis 提供了一个cache 接口
<!-- type:指定cache 接口的实现类型,mybatis 默认使用PerpetualCache
      要与ehcache 实现整合,需要配置type 为ehcache 的实现cache 接口的类型 -->
<cache type="" />
  • 过程
  1. 加入ehcache 的依赖
<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.0.2</version>
</dependency>
  1. 加入ehcache 的配置文件
  • 在resources 下配置ehcache.xml
<ehcache
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
        updateCheck="false">
      /* 当需要将数据存放到硬盘时的位置 */
    <diskStore path="D:\ehcache\resources"/>
    <defaultCache
            maxElementsInMemory="20000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
            maxElementsOnDisk="10000000"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"
    />
    <cache name="eternalCache"
           maxElementsInMemory="20000"
           eternal="true"
           overflowToDisk="true"
           diskPersistent="false"
           timeToLiveSeconds="0"
           diskExpiryThreadIntervalSeconds="120"
    />
</ehcache>
  1. 修改 属性值为***org.mybatis.caches.ehcache.EhcacheCache***

二级缓存的应用场景:

  1. 对访问次数多、实时性要求不高;
  2. 耗时查询

二级缓存的局限性:

  • 当存在大量数据在二级缓存时,如果存在一个数据使用了commit 操作,那么
    整个二级缓存数据都将被清空,导致数据缓存命中率低

Mybatis 逆向工程

  • 正对单表自动生成Mybatis 自动创建所需的代码(mapper.java、mapper.xml、opjo);
  • 常用的逆向工程的方式是由数据库生成java 代码

使用逆向工程

  • 建议使用java 程序的方式生成Java 代码
生成的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <context id="DB2Tables" targetRuntime="MyBatis3">
        <commentGenerator>
            <!-- 是否去除自动生成的注释 -->
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>
        <!-- Mysql数据库连接的信息:驱动类、连接地址、用户名、密码 -->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/javaend"
                        userId="root"
                        password="1006">
        </jdbcConnection>
        <!-- Oracle数据库
            <jdbcConnection driverClass="oracle.jdbc.OracleDriver"
                connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:yycg"
                userId="yycg"
                password="yycg">
            </jdbcConnection>
        -->

        <!-- 默认为false,把JDBC DECIMAL 和NUMERIC类型解析为Integer,为true时
        把JDBC DECIMAL 和NUMERIC类型解析为java.math.BigDecimal -->
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>

        <!-- targetProject:生成POJO类的位置 -->
        <javaModelGenerator targetPackage="com.pojo" targetProject=".\src">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false"/>
            <!-- 从数据库返回的值被清理前后的空格 -->
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>

        <!-- targetProject:mapper映射文件生成的位置 -->
        <sqlMapGenerator targetPackage="com.dao" targetProject=".\src">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false"/>
        </sqlMapGenerator>

        <!-- targetProject:mapper接口生成的的位置 -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.dao" targetProject=".\src">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false"/>
        </javaClientGenerator>

        <!-- 指定数据表 -->
        <table schema="" tableName="tb_orders"></table>
        <table schema="" tableName="tb_product"></table>
        <table schema="" tableName="tb_ordersitem"></table>
        <table schema="" tableName="tb_user"></table>

        <!-- 有些表的字段需要指定java类型
        <table schema="DB2ADMIN" tableName="ALLTYPES" domainObjectName="Customer" >
          <property name="useActualColumnNames" value="true"/>
          <generatedKey column="ID" sqlStatement="DB2" identity="true" />
          <columnOverride column="DATE_FIELD" property="startDate" />
          <ignoreColumn column="FRED" />
          <columnOverride column="LONG_VARCHAR_FIELD" jdbcType="VARCHAR" />
        </table> -->

    </context>
</generatorConfiguration>

执行生成程序
package com.mybatisStudy5_generator; /**
 * @ClassName StartGeneratorConfig
 * @Author 秃头的JJ
 * Date 2019/5/20 0020 22:05
 * Version 1.0
 */

import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class StartGeneratorConfig {
    public void generator() throws Exception {

        List<String> warnings = new ArrayList<String>();
        boolean overwrite = true;
        //指定 逆向工程配置文件
        File configFile = new File("mybatisStudy5_generator/src/main/resources/generatorConfig.xml");
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(configFile);
        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
                callback, warnings);
        myBatisGenerator.generate(null);

    }

    public static void main(String[] args) throws Exception {
        try {
            StartGeneratorConfig start = new StartGeneratorConfig();
            start.generator();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值