【MyBatis】五、MyBatis的缓存机制与逆向工程

MyBatis的缓存机制

MyBatis的一级缓存

MyBatis的一级缓存是默认开启的,是基于SqlSession级别的缓存,也就是说,只要是同一个sqlSession,只要执行的语句相同,则不会去数据库中进行查找,而是会从缓存中找到对应的结果。

MyBatis一级缓存失效的四种情况

  • 使用了不同的sqlsession对象
  • 同一个sqlsession对象,但查询条件不同
  • 两次查询之间进行了增删改操作(增删改操作会清空缓存)
  • 手动清空缓存(sqlsession.clearCache())

MyBatis二级缓存

MyBatis的二级缓存是SqlSessionFactory级别的,也就是说,通过同一个SqlSessionFactory创建的SqlSession对象所查询的结果都会被缓存,而在查询时也都会优先从缓存中获取结果。

二级缓存的开启

MyBatis的二级缓存默认是不开启的

  • 在核心配置文件(mybatis-config.xml)中配置属性cacheEnable=“true”,默认为true不用刻意配置

  • 在映射文件中设置标签:

    <mapper namespace="com.qinghe.mybatis.mapper.DynamicSQLMapper">
    
        <cache />
    
        <sql id="empColumn">eid, emp_name, age, sex, emailsql>
    
  • 对应的实体类必须序列化

    public class Emp implements Serializable {
    

注意:只有在sqlSession关闭或提交之后,信息才会被提交到二级缓存中。

    @Test
    public void testTwoCache() {
        try {
//            获取mybatis配置文件的字节输入流
            InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//            工厂模式,创建一个创建sqlSession的工厂,(通过刚刚获取到的输入流)
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//            创建一个sqlSession对象,开启自动提交
            SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
            CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
            System.out.println(mapper1.getEmpByEid(1));
//            只有sqlsession关闭或提交之后二级缓存才生效
            sqlSession1.commit();
            SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
            CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
            System.out.println(mapper2.getEmpByEid(1));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

注意:在两次查询之间进行了增删改操作的话,会使缓存失效

手动清空缓存不会清空二级缓存

二级缓存的相关信息

  • eviction属性:缓存回收策略

    • LRU(默认):最近最少使用策略
    • FIFO:先进先出
    • SOFT-软引用:移除基于垃圾回收器状态和软引用规则的对象
    • WEAK-弱引用:更积极的移除基于垃圾回收器状态和弱引用规则的对象
  • flushInterval属性:刷新间隔(二级缓存的清空间隔)

    默认为不刷新,只在进行了增删改之后刷新。

  • size属性:引用数目,正整数

    代表缓存中可以存储多少个对象,不要设置太大,容易造成内存溢出

  • readOnly属性:默认为false

    • true:缓存返回的对象为只读缓存,其会给调用者返回缓存对象相同的实例,因此这些对象不能修改,这提供了很大的性能优势
    • false:缓存返回的对象为读写缓存(通过序列化),这会慢一些但是保证了数据的安全性。

MyBatis的缓存查询顺序

  • 先查询二级缓存,因为二级缓存中可能会存在其他程序已经查询出来的数据,其可以直接拿来使用。
  • 如果二级缓存没有命中,会去查询一级缓存(还未提交到二级缓存的数据可能会存在于这里)
  • 如果一级缓存也没有命中,查询数据库
  • SqlSession关闭之后,将一级缓存中的内容存储到二级缓存

MyBatis整合EHCache

MyBatis作为持久层框架,其也提供了整合第三方缓存机制的接口,例如可以整合EHCache:

添加依赖:

        <dependency>
            <groupId>org.mybatis.cachesgroupId>
            <artifactId>mybatis-ehcacheartifactId>
            <version>1.2.1version>

        dependency>


        <dependency>
            <groupId>ch.qos.logbackgroupId>
            <artifactId>logback-classicartifactId>
            <version>1.2.3version>
        dependency>

添加encache的配置文件:ehcache.xml(文件名固定)


<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
    
    <diskStore path="D:\atguigu\ehcache"/>
    <defaultCache
            maxElementsInMemory="1000"
            maxElementsOnDisk="10000000"
            eternal="false"
            overflowToDisk="true"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
    defaultCache>
ehcache>

设置二级缓存的类型

  • 在xxxMapper.xml文件中设置二级缓存类型
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

加入logback日志

  • 存在SLF4J时,作为简易日志的log4j将失效,此时我们需要借助SLF4J的具体实现logback来打印日志。创建logback的配置文件logback.xml,名字固定,不可改变

<configuration debug="true">
    
    <appender name="STDOUT"
              class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            
            
            <pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%npattern>
        encoder>
    appender>
    
    
    <root level="DEBUG">
        
        <appender-ref ref="STDOUT" />
    root>
    
    <logger name="com.atguigu.crowd.mapper" level="DEBUG"/>
configuration>

EHCache配置文件说明

属性名 是否必须 作用
maxElementsInMemory 在内存中缓存的element的最大数目
maxElementsOnDisk 在磁盘上缓存的element的最大数目,若是0表示无穷大
eternal 设定缓存的elements是否永远不过期。 如果为true,则缓存的数据始终有效, 如果为false那么还要根据timeToIdleSeconds、timeToLiveSeconds判断
overflowToDisk 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
timeToIdleSeconds 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时, 这些数据便会删除,默认值是0,也就是可闲置时间无穷大
timeToLiveSeconds 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
diskSpoolBufferSizeMB DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区
diskPersistent 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false
diskExpiryThreadIntervalSeconds 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s, 相应的线程会进行一次EhCache中数据的清理工作
memoryStoreEvictionPolicy 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。 默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出

MyBatis逆向工程

引入依赖

<dependencies>
    
    
    <dependency>
        <groupId>org.mybatisgroupId>
        <artifactId>mybatisartifactId>
        <version>3.5.7version>
    dependency>
    
    <dependency>
        <groupId>junitgroupId>
        <artifactId>junitartifactId>
        <version>4.12version>
        <scope>testscope>
    dependency>
    
    
    <dependency>
        <groupId>com.mysqlgroupId>
        <artifactId>mysql-connector-jartifactId>
        <version>8.0.32version>
    dependency>

    <dependency>
        <groupId>log4jgroupId>
        <artifactId>log4jartifactId>
        <version>1.2.17version>
    dependency>


dependencies>

<build>
    
    <plugins>
        
        <plugin>
            <groupId>org.mybatis.generatorgroupId>
            <artifactId>mybatis-generator-maven-pluginartifactId>
            <version>1.3.0version>
            
            <dependencies>
                
                <dependency>
                    <groupId>org.mybatis.generatorgroupId>
                    <artifactId>mybatis-generator-coreartifactId>
                    <version>1.3.2version>
                dependency>
                
                <dependency>
                    <groupId>com.mchangegroupId>
                    <artifactId>c3p0artifactId>
                    <version>0.9.2version>
                dependency>
                
                <dependency>
                    <groupId>mysqlgroupId>
                    <artifactId>mysql-connector-javaartifactId>
                    <version>8.0.27version>
                dependency>
            dependencies>
        plugin>
    plugins>
build>

创建mybatis核心配置文件

mybatis-config.xml:


DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    
    <properties resource="jdbc.properties"/>
    
    <typeAliases>
        
        
        <package name="com.qinghe.mybatis.pojo">package>
    typeAliases>

    
    <environments default="development">
        <environment id="development">
            
            <transactionManager type="JDBC"/>
            
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            dataSource>
        environment>
    environments>
    
    <mappers>
        
        

        
        
        <package name="">package>
    mappers>
configuration>

创建逆向工程的配置文件

generatorConfig.xml(不得改名)


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="MyBatis3Simple">
        
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/mybatis"
                        userId="root"
                        password="123456">
        jdbcConnection>
        

        <javaModelGenerator targetPackage="com.qinghe.mybatis.pojo" targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
        javaModelGenerator>
        
        <sqlMapGenerator targetPackage="com.qinghe.mybatis.mapper"
                         targetProject=".\src\main\resources">
            <property name="enableSubPackages" value="true" />
        sqlMapGenerator>
        
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="com.qinghe.mybatis.mapper" targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
        javaClientGenerator>
        
        
        
        <table tableName="t_emp" domainObjectName="Emp"/>
        <table tableName="t_dept" domainObjectName="Dept"/>
    context>
generatorConfiguration>

之后在右侧的plugins中执行mybatis-generator就可以生成文件了,注意这样会将数据库中的下划线字段映射为驼峰,这样的生成方式只有基础的CRUD功能

MyBatis逆向工程奢华尊享版

在高级的MyBatis生成文件中,我们会生成类似于Mybatis-plus的sql映射,以以下方式使用:

注意xxxSeletive方法在操作时会不插入值为null的数据

    @Test
    public void test1() {
        try {
            InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory =  new SqlSessionFactoryBuilder().build(is);
            SqlSession sqlSession = sqlSessionFactory.openSession(true);
            EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
//            List list = mapper.selectByExample(null);
//            创建条件
            EmpExample example = new EmpExample();
//            and条件这样添加
            example.createCriteria().andEmpNameEqualTo("张三").andAgeBetween(20, 90);
//            or条件这样添加
            example.or().andDidIsNotNull();
            List<Emp> list = mapper.selectByExample(example);
            list.forEach(item -> {
                System.out.println(item);
            });
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

MyBatis分页插件

配置依赖

        
        <dependency>
            <groupId>com.github.pagehelpergroupId>
            <artifactId>pagehelperartifactId>
            <version>5.2.0version>
        dependency>

在mybatis-config中配置分页插件,注意其位置顺序:

properties、settings、typeAliases、typeHandlers、objectFactory、objectWrapperFactory、reflectorFactory、plugins、environments、databaseIdProvider、mappers

    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">plugin>
    plugins>

使用:

    @Test
    public void testPageHelper() {
        try {
            InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            SqlSession sqlSession = sqlSessionFactory.openSession(true);
            EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

//            开启PageHelper分页
//            可以使用Page对象接收分页,page对象中会存储一些基本信息
            Page<Object> page = PageHelper.startPage(3, 2);
            List<Emp> list = mapper.selectByExample(null);
//            也可以在这里使用PageInfo对象接收分页信息,这之中有全部的详细信息
//            第二个形参代表导航的数量:......4、5、6、7、8、9......(例如这种就是有五个)
            PageInfo<Emp> pageInfo = new PageInfo<>(list, 5);
            System.out.println(page);
            System.out.println(pageInfo);
            /**
             * limit index, pageSize
             *
             */
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

Page对象中的信息:

Page{count=true, pageNum=3, pageSize=2, startRow=4, endRow=6, total=10, pages=5, reasonable=false, pageSizeZero=false}

[Emp{eid=5, empName=‘田七’, age=22, sex=‘男’, email=‘[email protected]’, did=2}, Emp{eid=6, empName=‘a’, age=null, sex=‘null’, email=‘null’, did=null}]

PageInfo对象中的信息:

PageInfo{pageNum=3, pageSize=2, size=2, startRow=5, endRow=6, total=10, pages=5, list=Page{count=true, pageNum=3, pageSize=2, startRow=4, endRow=6, total=10, pages=5, reasonable=false, pageSizeZero=false}

[Emp{eid=5, empName=‘田七’, age=22, sex=‘男’, email=‘[email protected]’, did=2}, Emp{eid=6, empName=‘a’, age=null, sex=‘null’, email=‘null’, did=null}],

prePage=2, nextPage=4, isFirstPage=false, isLastPage=false, hasPreviousPage=true, hasNextPage=true, navigatePages=5, navigateFirstPage=1, navigateLastPage=5, navigatepageNums=[1, 2, 3, 4, 5]}

你可能感兴趣的:(Mybatis,mybatis,sql,python)