前言

本文主要讲解Mybatis的以下知识点:

  • Mybatis缓存

    • 一级缓存
    • 二级缓存
    • 与Ehcache整合
  • Mapper代理
    • 使用Mapper代理就不用写实现类了
  • 逆向工程
    • 自动生成代码

Mybatis缓存

缓存的意义

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

mybatis提供一级缓存和二级缓存

  • mybatis一级缓存是一个SqlSession级别,sqlsession只能访问自己的一级缓存的数据
  • 二级缓存是跨sqlSession,是mapper级别的缓存,对于mapper级别的缓存不同的sqlsession是可以共享的。

看完上面对Mybatis的缓存的解释,我们发现Mybatis的缓存和Hibernate的缓存是极为相似的..

Mybatis一级缓存

Mybatis的一级缓存原理

第一次发出一个查询sql,sql查询结果写入sqlsession的一级缓存中,缓存使用的数据结构是一个map<key,value>

  • key:hashcode+sql+sql输入参数+输出参数(sql的唯一标识)
  • value:用户信息

同一个sqlsession再次发出相同的sql,就从缓存中取不走数据库。如果两次中间出现commit操作(修改、添加、删除),本sqlsession中的一级缓存区域全部清空,下次再去缓存中查询不到所以要从数据库查询,从数据库查询到再写入缓存。

Mybatis一级缓存值得注意的地方:

  • Mybatis默认就是支持一级缓存的,并不需要我们配置.
  • mybatis和spring整合后进行mapper代理开发,不支持一级缓存,mybatis和spring整合,spring按照mapper的模板去生成mapper代理对象,模板中在最后统一关闭sqlsession。

Mybatis二级缓存

二级缓存原理:

二级缓存的范围是mapper级别(mapper同一个命名空间),mapper以命名空间为单位创建缓存数据结构,结构是map<key、value>。

Mybatis二级缓存配置

需要我们在Mybatis的配置文件中配置二级缓存

  1. <!-- 全局配置参数 -->
  2. <settings>
  3. <!-- 开启二级缓存 -->
  4. <setting name="cacheEnabled" value="true"/>
  5. </settings>

上面已经说了,二级缓存的范围是mapper级别的,因此我们的Mapper如果要使用二级缓存,还需要在对应的映射文件中配置..

  1. <cache/>

查询结果映射的pojo序列化

mybatis二级缓存需要将查询结果映射的pojo实现 java.io.serializable接口,如果不实现则抛出异常:

  1. org.apache.ibatis.cache.CacheException: Error serializing object. Cause: java.io.NotSerializableException: cn.itcast.mybatis.po.User

二级缓存可以将内存的数据写到磁盘,存在对象的序列化和反序列化,所以要实现java.io.serializable接口。

如果结果映射的pojo中还包括了pojo,都要实现java.io.serializable接口。

禁用二级缓存

对于变化频率较高的sql,需要禁用二级缓存:

在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。、、

  1. <select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">

刷新缓存

有的同学到这里可能会有一个疑问:为什么缓存我们都是在查询语句中配置??而使用增删改的时候,缓存默认就会被清空【刷新了】???

缓存其实就是为我们的查询服务的,对于增删改而言,如果我们的缓存保存了增删改后的数据,那么再次读取时就会读到脏数据了

我们在特定的情况下,还可以单独配置刷新缓存【但不建议使用】flushCache,默认是的true


  1. <update id="updateUser" parameterType="cn.itcast.mybatis.po.User" flushCache="false">
  2. update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
  3. </update>

了解Mybatis缓存的一些参数

mybatis的cache参数只适用于mybatis维护缓存。

  1. flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。
  2. size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值是1024
  3. readOnly(只读)属性可以被设置为truefalse。只读的缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false
  4. 如下例子:
  5. <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
  6. 这个更高级的配置创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会导致冲突。可用的收回策略有, 默认的是 LRU:
  7. 1.LRU 最近最少使用的:移除最长时间不被使用的对象。
  8. 2.FIFO 先进先出:按对象进入缓存的顺序来移除它们。
  9. 3.SOFT 软引用:移除基于垃圾回收器状态和软引用规则的对象。
  10. 4.WEAK 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

mybatis和ehcache缓存框架整合

ehcache是专门用于管理缓存的,Mybatis的缓存交由ehcache管理会更加得当..

mybatis中提供一个cache接口,只要实现cache接口就可以把缓存数据灵活的管理起来

整合jar包

  • mybatis-ehcache-1.0.2.jar
  • ehcache-core-2.6.5.jar

ehcache对cache接口的实现类:

ehcache.xml配置信息

这个xml配置文件是配置全局的缓存管理方案


  1. <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2. xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
  3. <!--diskStore:缓存数据持久化的目录 地址 -->
  4. <diskStore path="F:\develop\ehcache" />
  5. <defaultCache
  6. maxElementsInMemory="1000"
  7. maxElementsOnDisk="10000000"
  8. eternal="false"
  9. overflowToDisk="false"
  10. diskPersistent="true"
  11. timeToIdleSeconds="120"
  12. timeToLiveSeconds="120"
  13. diskExpiryThreadIntervalSeconds="120"
  14. memoryStoreEvictionPolicy="LRU">
  15. </defaultCache>
  16. </ehcache>

如果我们Mapper想单独拥有一些特性,需要在mapper.xml中单独配置


  1. <!-- 单位:毫秒 -->
  2. <cache type="org.mybatis.caches.ehcache.EhcacheCache">
  3. <property name="timeToIdleSeconds" value="12000"/>
  4. <property name="timeToLiveSeconds" value="3600"/>
  5. <!-- 同ehcache参数maxElementsInMemory -->
  6. <property name="maxEntriesLocalHeap" value="1000"/>
  7. <!-- 同ehcache参数maxElementsOnDisk -->
  8. <property name="maxEntriesLocalDisk" value="10000000"/>
  9. <property name="memoryStoreEvictionPolicy" value="LRU"/>
  10. </cache>

应用场景与局限性

应用场景

对查询频率高,变化频率低的数据建议使用二级缓存。

对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度

业务场景比如:

  • 耗时较高的统计分析sql、
  • 电话账单查询sql等。

实现方法如下:通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,比如设置为30分钟、60分钟、24小时等,根据需求而定。

局限性

mybatis局限性

mybatis二级缓存对细粒度的数据级别的缓存实现不好,比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,此时如果使用mybatis的二级缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,因为mybaits的二级缓存区域以mapper为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空。解决此类问题需要在业务层根据需求对数据有针对性缓存。

Mapper代理方式

Mapper代理方式的意思就是:程序员只需要写dao接口,dao接口实现对象由mybatis自动生成代理对象。

经过我们上面的几篇博文,我们可以发现我们的DaoImpl是十分重复的...

1 dao的实现类中存在重复代码,整个mybatis操作的过程代码模板重复(先创建sqlsession、调用sqlsession的方法、关闭sqlsession)

2、dao的实现 类中存在硬编码,调用sqlsession方法时将statement的id硬编码。


以前的重复代码和硬编码如下


  1. public class StudentDao {
  2. public void add(Student student) throws Exception {
  3. //得到连接对象
  4. SqlSession sqlSession = MybatisUtil.getSqlSession();
  5. try{
  6. //映射文件的命名空间.SQL片段的ID,就可以调用对应的映射文件中的SQL
  7. sqlSession.insert("StudentID.add", student);
  8. sqlSession.commit();
  9. }catch(Exception e){
  10. e.printStackTrace();
  11. sqlSession.rollback();
  12. throw e;
  13. }finally{
  14. MybatisUtil.closeSqlSession();
  15. }
  16. }
  17. public static void main(String[] args) throws Exception {
  18. StudentDao studentDao = new StudentDao();
  19. Student student = new Student(3, "zhong3", 10000D);
  20. studentDao.add(student);
  21. }
  22. }

Mapper开发规范

想要Mybatis帮我们自动生成Mapper代理的话,我们需要遵循以下的规范:

1、mapper.xml中namespace指定为mapper接口的全限定名

  • 此步骤目的:通过mapper.xml和mapper.java进行关联

2、mapper.xml中statement的id就是mapper.java中方法名

3、mapper.xml中statement的parameterType和mapper.java中方法输入参数类型一致

4、mapper.xml中statement的resultType和mapper.java中方法返回值类型一致.

再次说明:statement就是我们在mapper.xml文件中命名空间+sql指定的id

Mapper代理返回值问题

mapper接口方法返回值:

  • 如果是返回的单个对象,返回值类型是pojo类型,生成的代理对象内部通过selectOne获取记录
  • 如果返回值类型是集合对象,生成的代理对象内部通过selectList获取记录。

Mybatis解决JDBC编程的问题

1、数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。

  • 解决:在SqlMapConfig.xml中配置数据链接池,使用连接池管理数据库链接。

2、Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。

  • 解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离

3、向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。

  • 解决:Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型

4、对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。

  • 解决:Mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型

Mybatis逆向工程

在Intellij idea下,没有学习Maven的情况下使用Mybatis的逆向工程好像有点复杂,资料太少了...找到的资料好像也行不通...

于是学完Maven之后,我就再来更新Idea下使用Mybatis的逆向工程配置...

借鉴博文:http://blog.csdn.net/for_my_life/article/details/51228098

修改pom.xml文件

向该工程添加逆向工程插件..


  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <groupId>asdf</groupId>
  7. <artifactId>asdf</artifactId>
  8. <version>1.0-SNAPSHOT</version>
  9. <build>
  10. <finalName>zhongfucheng</finalName>
  11. <plugins>
  12. <plugin>
  13. <groupId>org.mybatis.generator</groupId>
  14. <artifactId>mybatis-generator-maven-plugin</artifactId>
  15. <version>1.3.2</version>
  16. <configuration>
  17. <verbose>true</verbose>
  18. <overwrite>true</overwrite>
  19. </configuration>
  20. </plugin>
  21. </plugins>
  22. </build>
  23. </project>

generatorConfig.xml配置文件


  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE generatorConfiguration
  3. PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  4. "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
  5. <generatorConfiguration>
  6. <!--
  7. <properties resource="conn.properties" />
  8. -->
  9. <!-- 处理1,这里的jar包位置可能需要修改 -->
  10. <classPathEntry location="C:\mybatisMaven\lib\mysql-connector-java-5.1.7-bin.jar"/>
  11. <!-- 指定运行环境是mybatis3的版本 -->
  12. <context id="testTables" targetRuntime="MyBatis3">
  13. <commentGenerator>
  14. <!-- 是否取消注释 -->
  15. <property name="suppressAllComments" value="true" />
  16. <!-- 是否生成注释代时间戳 -->
  17. <property name="suppressDate" value="true" />
  18. </commentGenerator>
  19. <!-- 处理2 jdbc 连接信息,看看库是否存在 -->
  20. <jdbcConnection driverClass="com.mysql.jdbc.Driver"
  21. connectionURL="jdbc:mysql://localhost:3306/scm?useUnicode=true&characterEncoding=UTF-8" userId="root" password="root">
  22. </jdbcConnection>
  23. <!--处理3 targetPackage指定模型在生成在哪个包 ,targetProject指定项目的src,-->
  24. <javaModelGenerator targetPackage="zhongfucheng.entity"
  25. targetProject="src/main/java">
  26. <!-- 去除字段前后空格 -->
  27. <property name="trimStrings" value="false" />
  28. </javaModelGenerator>
  29. <!--处理4 配置SQL映射文件生成信息 -->
  30. <sqlMapGenerator targetPackage="zhongfucheng.dao"
  31. targetProject="src/main/java" />
  32. <!-- 处理5 配置dao接口生成信息-->
  33. <javaClientGenerator type="XMLMAPPER" targetPackage="zhongfucheng.dao" targetProject="src/main/java" />
  34. <table tableName="account" domainObjectName="Account"/>
  35. <table tableName="supplier" domainObjectName="Supplier"/>
  36. </context>
  37. </generatorConfiguration>

使用插件步骤

最后生成代码

如果对我们上面generatorConfig.xml配置的包信息不清楚的话,那么可以看一下我们的完整项目结构图...

因为我们在Idea下是不用写对应的工程名字的,而在eclipse是有工程名字的。

总结

  • Mybatis的一级缓存是sqlSession级别的。只能访问自己的sqlSession内的缓存。如果Mybatis与Spring整合了,Spring会自动关闭sqlSession的。所以一级缓存会失效的。

  • 一级缓存的原理是map集合,Mybatis默认就支持一级缓存

  • 二级缓存是Mapper级别的。只要在Mapper命名空间下都可以使用二级缓存。需要我们自己手动去配置二级缓存

  • Mybatis的缓存我们可以使用Ehcache框架来进行管理,Ehcache实现Cache接口就代表使用Ehcache来环境Mybatis缓存。

  • 由于之前写的DaoImpl是有非常多的硬编码的。可以使用Mapper代理的方式来简化开发

    • 命名空间要与JavaBean的全类名相同
    • sql片段语句的id要与Dao接口的方法名相同
    • 方法的参数和返回值要与SQL片段的接收参数类型和返回类型相同。

    如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y

Mybatis【逆向工程,缓存,代理】知识要点的更多相关文章

  1. Hibernate【缓存】知识要点

    对象状态 Hibernate中对象的状态: 临时/瞬时状态 持久化状态 游离状态 学习Hibernate的对象状态是为了更清晰地知道Hibernate的设计思想,以及是一级缓存的基础...当然啦,也就 ...

  2. mybatis 逆向工程使用姿势不对,把表清空了,心里慌的一比,于是写了个插件。

    使用mybatis逆向工程的时候,delete方法的使用姿势不对,导致表被清空了,在生产上一刷新后发现表里没数据了,一股凉意从脚板心直冲天灵盖. 于是开发了一个拦截器,并写下这篇文章记录并分享. 这锅 ...

  3. 9.Mybatis一级缓存和二级缓存

    所谓的缓存呢?其实原理很简单,就是在保证你查询的数据是正确的情况下,没有去查数据库,而是直接查找的内存,这样做有利于缓解数据库的压力,提高数据库的性能,Mybatis中有提供一级缓存和二级缓存. 学习 ...

  4. Mybatis学习记录(七)----Mybatis查询缓存

    1. 什么是查询缓存 mybatis提供查询缓存,用于减轻数据压力,提高数据库性能. mybaits提供一级缓存,和二级缓存. 一级缓存是SqlSession级别的缓存.在操作数据库时需要构造 sql ...

  5. 八 mybatis查询缓存(一级缓存,二级缓存)和ehcache整合

    1       查询缓存 1.1     什么是查询缓存 mybatis提供查询缓存,用于减轻数据压力,提高数据库性能. mybaits提供一级缓存,和二级缓存.

  6. spring、spring mvc、mybatis框架整合基本知识

    学习了一个多月的框架知识了,这两天很想将它整合一下.网上看了很多整合案例,基本都是基于Eclipse的,但现在外面公司基本都在用Intellij IDEA了,所以结合所学知识,自己做了个总结,有不足之 ...

  7. Web缓存相关知识整理

    一.前言  工作上遇到一个这样的需求,一个H5页面在APP端,如果勾选已读状态,则下次打开该链接,会跳过此页面.用到了HTML5 的本地存储 API 中的 localStorage作为解决方案,回顾了 ...

  8. JAVAEE——Mybatis第二天:输入和输出映射、动态sql、关联查询、Mybatis整合spring、Mybatis逆向工程

    1. 学习计划 1.输入映射和输出映射 a) 输入参数映射 b) 返回值映射 2.动态sql a) If标签 b) Where标签 c) Sql片段 d) Foreach标签 3.关联查询 a) 一对 ...

  9. Mybatis的缓存

    1.缓存是什么 在 Mybatis 里面,所谓的缓存就是将已经查询过的记录放在内存的缓冲区或文件上,这样如果再次查询,可以通过配置的策略,命中已经查询过的记录,从而提高查询的效率. Mybatis 的 ...

随机推荐

  1. Javascript原型继承容易忽略的错误

    编写Javascript的开发者都知道,JS虽然没有类(ES6添加了class语法),但是可以模拟出OOP语言的类和面向对象的概念,比如我们都知道的一句话,Javascript中处处是对象,而面向对象 ...

  2. PHP码农在Golang压力下的生存之道-PHP性能优化实践

    随着国内Golang的火爆,phper的生存压力越来越大,在一次内部技术讨论中,gopher甚至提出,要什么php,写php的全部开掉,唉,码农何苦为难码农. 本文试图寻找一种有效实践,减少php w ...

  3. Maven服务器

    Maven私服仓库管理: Nexus 3.0 使用nexus3.X搭建maven私服在Centos7环境中-详细教程

  4. ECharts 高度宽度自适应(转载)

    最近在写一个地图类的应用,用的是echarts的图表,然而一上来就一脸懵逼,如果父级容器的height/width属性设置为百分比的形式,那么echarts就会warning,且不能正常的生成图表.所 ...

  5. 用Open SSH生成公钥和私钥(Win)

    也可以使用 dsa 加密算法进行加密,命令如下: ssh-keygen -t dsa

  6. FFmepg 如何在 window 上使用?

    下载FFmepg官网库直接使用即可. avdevice.lib avcodec.lib avfilter.lib avformat.lib avutil.lib postproc.lib swresa ...

  7. scrapy学习总结

    1.为了配合XPath,Scrapy除了提供了 Selector 之外,还提供了方法来避免每次从response中提取数据时生成selector的麻烦 Selector有四个基本的方法(点击相应的方法 ...

  8. Ansible自动化运维笔记2(Ansible的组件介绍)

    1.Ansible Inventory (1)静态主机文件 默认的ansible invetory是/etc/hosts文件,可以通过ANSIBLE_HOSTS环境变量或者通过运行命令的时候加上-i ...

  9. __proto__ 与 prototype

    先来做个复习,ES5中有有几种数据类型呢? 5种基本数据类型 Undefined Null Boolean Number String 1种复杂数据类型 Object 除了基本数据类型,万物皆对象,记 ...

  10. 讯飞语音JavaWeb语音合成解决方案

    在线语音合成 将文字信息转化为声音信息,给应用配上"嘴巴".我们提供了众多极具特色的发音人(音库)供您选择.其合成音在音色.自然度等方面的表现均接近甚至超过了人声.这种语音合成体验 ...