查询缓存&&逆向工程

1.查询缓存

  一级缓存:同一个SqlSession对象,MyBatis默认开启一级缓存

  如果用同样的SqlSession对象查询相同的数据,则只会在第一次查询时向数据库发送Sql语句并将查询的结果放入到SqlSession中(作为缓存存在),后续再次查询该对象即可(即省略了数据库的访问)

  

     // Connection - SqlSession操作Mybatis
        // conf.xml->reader
        Reader reader = Resources.getResourceAsReader("conf.xml");
        // reader->sqlSession

        // 可以通过build的第二参数 指定数据库环境
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader, "development");
        SqlSession session = sessionFactory.openSession();

        StudentMapper studentMapper = session.getMapper(StudentMapper.class);
        Student student = studentMapper.queryStudentByStuno(2);
        Student student2 = studentMapper.queryStudentByStuno(2);
        
        //增删改操作...
        session.commit();
        Student student3 = studentMapper.queryStudentByStuno(2);
        
        System.out.println(student.getStuName());
        System.out.println(student2.getStuName());
        System.out.println(student3.getStuName());
        session.close();




结果:
DEBUG [main] - ==>  Preparing: select * from student1 where stuno=2 
DEBUG [main] - ==> Parameters: 
DEBUG [main] - <==      Total: 1
DEBUG [main] - ==>  Preparing: select * from student1 where stuno=2 
DEBUG [main] - ==> Parameters: 
DEBUG [main] - <==      Total: 1
ls
ls
ls

  二级缓存:

      Mybatis自带二级缓存:同一个namespace生成的XxxMapper对象

      MyBatis默认关闭二级缓存,需要手工打开

回顾:namespace的值就是接口的全类名(包名、类名),通过接口可以产生代理对象(Mapper对象)

    -->namespace决定了Mapper对象的产生

  结论:只要产生的xxxMapper对象来自于同一个namespace,则这些对象共享二级缓存。

如果是同一个SqlSession对象进行多次相同的查询,则直接进入一级缓存查询

如果不是同一个SqlSession对象进行多次相同的查询(但是均来自于同一个namespace),则进入二级缓存查询

     // Connection - SqlSession操作Mybatis
        // conf.xml->reader
        Reader reader = Resources.getResourceAsReader("conf.xml");
        // reader->sqlSession

        // 可以通过build的第二参数 指定数据库环境
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader, "development");
        
        
        //第一次查询
        SqlSession session = sessionFactory.openSession();
        StudentMapper studentMapper = session.getMapper(StudentMapper.class);
        
        Student student = studentMapper.queryStudentByStuno(2);
        
        //第二次查询
        SqlSession session2 = sessionFactory.openSession();
        StudentMapper studentMapper2 = session2.getMapper(StudentMapper.class);
        
        Student student2 = studentMapper2.queryStudentByStuno(2);
        
        
        System.out.println(student.getStuName());
        System.out.println(student2.getStuName());
        session.close();
     session2.close(); 结果: DEBUG [main]
- Opening JDBC Connection DEBUG [main] - Created connection 481511146. DEBUG [main] - Setting autocommit to false on JDBC Connection [oracle.jdbc.driver.T4CConnection@1cb346ea] DEBUG [main] - ==> Preparing: select * from student1 where stuno=2 DEBUG [main] - ==> Parameters: DEBUG [main] - <== Total: 1 DEBUG [main] - Opening JDBC Connection DEBUG [main] - Created connection 1060042118. DEBUG [main] - Setting autocommit to false on JDBC Connection [oracle.jdbc.driver.T4CConnection@3f2ef586] DEBUG [main] - ==> Preparing: select * from student1 where stuno=2 DEBUG [main] - ==> Parameters: DEBUG [main] - <== Total: 1 ls ls 原因:未开启二级缓存

      手工开启二级缓存:

  a./MyBatisProject3/src/conf.xml

<!--开启二级缓存  -->
        <setting name="cacheEnabled" value="true"/>

  b.在具体的mapper.xml中声明开启

  /MyBatisProject3/src/org/myy/mapper/studentMapper.xml 

<!--声明此namespace开启二级缓存 -->
    <cache />

根据异常提示java.io.NotSerializableException: 可知,MyBatis缓存是将对象放入硬盘文件中

  ->准备缓存的对象,必须实现了序列化接口(如果开启的缓存namespace="org.myy.mapper.StudentMapper")

  可知序列化对象为Student,因此需要将Student序列化(序列化Student类,以及Student的级联属性和父类

public class Student implements Serializable
...

  序列化:内存->硬盘

  反序列化:硬盘->内存

触发将对象写入二级缓存的时机:SqlSession对象的close()方法

     // Connection - SqlSession操作Mybatis
        // conf.xml->reader
        Reader reader = Resources.getResourceAsReader("conf.xml");
        // reader->sqlSession

        // 可以通过build的第二参数 指定数据库环境
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader, "development");
        
        
        //第一次查询
        SqlSession session = sessionFactory.openSession();
        StudentMapper studentMapper = session.getMapper(StudentMapper.class);
        
        Student student = studentMapper.queryStudentByStuno(2);
        
        session.close();//触发将对象写入二级缓存的时机
        //第二次查询
        SqlSession session2 = sessionFactory.openSession();
        StudentMapper studentMapper2 = session2.getMapper(StudentMapper.class);
        
        Student student2 = studentMapper2.queryStudentByStuno(2);
        
        
        System.out.println(student.getStuName());
        System.out.println(student2.getStuName());
        
        
        
        
        session2.close();

结果:

DEBUG [main] - Cache Hit Ratio [org.myy.mapper.StudentMapper]: 0.0
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 997850486.
DEBUG [main] - Setting autocommit to false on JDBC Connection [oracle.jdbc.driver.T4CConnection@3b79fd76]
DEBUG [main] - ==> Preparing: select * from student1 where stuno=2
DEBUG [main] - ==> Parameters:
DEBUG [main] - <== Total: 1
DEBUG [main] - Resetting autocommit to true on JDBC Connection [oracle.jdbc.driver.T4CConnection@3b79fd76]
DEBUG [main] - Closing JDBC Connection [oracle.jdbc.driver.T4CConnection@3b79fd76]
DEBUG [main] - Returned connection 997850486 to pool.
DEBUG [main] - Cache Hit Ratio [org.myy.mapper.StudentMapper]: 0.5
ls
ls

 

 注意:二级缓存的范围是同一个namespace,如果有多个xxMapper.xml的namespace值相同,则通过这些xxxMapper.xml产生的xxMapper对象仍然共享二级缓存

  禁用:select标签中useCache="false"

<select id="queryStudentByStuno" parameterType="int" resultMap="studentMapping" useCache="false">
        select * from student1 where stuno=${value}
    </select>

  清理:a.与清理一级缓存的方法相同

      commit();(一般执行增删改时,会清理掉缓存,设计的原因:是为了防止脏数据)

      在二级缓存中,commit()不能时查询自身的commit。

      commit会清理一级和二级缓存,但是清理二级缓存时,不能是查询自身的commit();

     b.在select标签中增加属性flushCache="true"

<select id="queryStudentByStuno" parameterType="int" resultMap="studentMapping" useCache="true" flushCache="true">
        select * from student1 where stuno=${value}
    </select>

  命中率:1:0.0

      2:0.5

      3:0.6666666

      4.0.75  

DEBUG [main] - Cache Hit Ratio [org.myy.mapper.StudentMapper]: 0.0
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 997850486.
DEBUG [main] - Setting autocommit to false on JDBC Connection [oracle.jdbc.driver.T4CConnection@3b79fd76]
DEBUG [main] - ==>  Preparing: select * from student1 where stuno=2 
DEBUG [main] - ==> Parameters: 
DEBUG [main] - <==      Total: 1
DEBUG [main] - Resetting autocommit to true on JDBC Connection [oracle.jdbc.driver.T4CConnection@3b79fd76]
DEBUG [main] - Closing JDBC Connection [oracle.jdbc.driver.T4CConnection@3b79fd76]
DEBUG [main] - Returned connection 997850486 to pool.
DEBUG [main] - Cache Hit Ratio [org.myy.mapper.StudentMapper]: 0.5
ls
ls
DEBUG [main] - Cache Hit Ratio [org.myy.mapper.StudentMapper]: 0.6666666666666666
DEBUG [main] - Cache Hit Ratio [org.myy.mapper.StudentMapper]: 0.75

  三方提供的二级缓存

    ehcache、mecache

    想要整合三方提供的二级缓存(或者自定义二级缓存),必须实现org.apache.ibatis.cache.Cache接口,该接口的默认实现类是PerpetCache

    整合ehcache二级缓存:

    a.添加jar包

    Ehcache-core.jar

    mybatis-Ehcache.jar

    slf4j-api.jar

    b.编写ehcache配置文件 Ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">
    <!--
       diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数解释如下:
       user.home – 用户主目录
       user.dir  – 用户当前工作目录
       java.io.tmpdir – 默认临时文件路径
       当二级缓存的对象超过内存限制时(缓存对象的个数>maxElementsInMemory),存放入的硬盘文件
     -->
    <diskStore path="D:	estEhcache"/>
    <!--
       defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。
     -->
    <!--
      name:缓存名称。
      maxElementsInMemory:设置在内存中缓存对象的最大个数
      maxElementsOnDisk:社渚在硬盘中最大缓存个数。
      eternal:设置缓存是否永远过期,一但设置了,timeout将不起作用。
      overflowToDisk:当内存中缓存的对象个数超过maxElementsInMemory的时候,是否转移到硬盘中
      timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
      timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.也就是对象存活时间无穷大。
      diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
      diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
      diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
      memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
      clearOnFlush:内存数量最大时是否清除。
      memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
      FIFO,first in first out,这个是大家最熟的,先进先出。
      LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
      LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
   -->
<defaultCache
        
        maxElementsInMemory="10000"
        maxElementsOnDisk="1000000"
        eternal="false"
        overflowToDisk="false"
        timeToIdleSeconds="100"
        timeToLiveSeconds="100"
        diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU"/>

<cache
        name="cloud_user"
        eternal="false"
        maxElementsInMemory="5000"
        overflowToDisk="false"
        diskPersistent="false"
        timeToIdleSeconds="1800"
        timeToLiveSeconds="1800"
        memoryStoreEvictionPolicy="LRU"/>
 
</ehcache>
 

  c.开启EhCache二级缓存

/MyBatisProject3/src/Ehcache.xml

<cache type="org.mybatis.caches.ehcache.EhcacheCache">
    <!--通过property覆盖Ehcache.xml中的值  -->
        <property name="maxElementsInMemory" value="1000"/>
    </cache>

2.逆向工程

  表、类、接口、mapper.xml四者密切相关,因此当知道一个的时候,其他三个应该可以自动生成。

  表->其他三个

  a.mybatis-generaotr-core.jar、mybatis.jar、ojdbc.jarS

  b.逆向工程的配置文件generator.xml

/MyBatisgenerator/src/generator.xml

<?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>
   <!--
            suppressAllComments属性值:
                true:自动生成实体类、SQL映射文件时没有注释
                true:自动生成实体类、SQL映射文件,并附有注释
          -->
  <property name="suppressAllComments" value="true" />
 </commentGenerator>
 
 
 <!-- 数据库连接信息 -->
  <jdbcConnection driverClass="oracle.jdbc.OracleDriver"
   connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:mldn" 
   userId="scott"  password="tiger">
  </jdbcConnection>
  <!-- 
            forceBigDecimals属性值: 
                true:把数据表中的DECIMAL和NUMERIC类型,
解析为JAVA代码中的java.math.BigDecimal类型 
                false(默认):把数据表中的DECIMAL和NUMERIC类型,
解析为解析为JAVA代码中的Integer类型 
        -->
 <javaTypeResolver>
      <property name="forceBigDecimals" value="false" />
 </javaTypeResolver>
 <!-- 
        targetProject属性值:实体类的生成位置  
        targetPackage属性值:实体类所在包的路径
    -->
 <javaModelGenerator targetPackage="org.myy.entity"
                            targetProject=".src">
  <!-- trimStrings属性值:
            true:对数据库的查询结果进行trim操作
            false(默认):不进行trim操作       
          -->
  <property name="trimStrings" value="true" />
 </javaModelGenerator>
 <!-- 
        targetProject属性值:SQL映射文件的生成位置  
        targetPackage属性值:SQL映射文件所在包的路径
    -->
  <sqlMapGenerator targetPackage="org.myy.mapper" 
            targetProject=".src">
  </sqlMapGenerator>
  <!-- 生成动态代理的接口  -->
 <javaClientGenerator type="XMLMAPPER" targetPackage="org.myy.mapper" targetProject=".src">
 </javaClientGenerator>
 
 <!-- 指定数据库表  -->
  <table tableName="Student1"> </table>
  <table tableName="studentCard"> </table>
  <table tableName="studentClass"> </table>
 </context>
</generatorConfiguration>

/MyBatisgenerator/src/org/myy/test/Test.java

package org.myy.test;

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

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


public class Test {
    public static void main(String[] args) throws Exception, XMLParserException {
        
        File file=new File("src/generator.xml");//配置文件
        
        List<String> warnings=new ArrayList<String>();
        ConfigurationParser cp=new ConfigurationParser(warnings);
        
        Configuration config=cp.parseConfiguration(file);
        
        DefaultShellCallback callback=new DefaultShellCallback(true);
        
        //逆向工程的核心类
        MyBatisGenerator generator=new MyBatisGenerator(config,callback,warnings);
        generator.generate(null);
    }
}
原文地址:https://www.cnblogs.com/mayouyou/p/13234591.html