Mybatis【逆向工程,缓存,代理】知识要点

前言

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

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

Mybatis缓存

缓存的意义mysql

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

 

这里写图片描述

 

mybatis提供一级缓存和二级缓存程序员

 

这里写图片描述

 

  • mybatis一级缓存是一个SqlSession级别,sqlsession只能访问本身的一级缓存的数据
  • 二级缓存是跨sqlSession,是mapper级别的缓存,对于mapper级别的缓存不一样的sqlsession是能够共享的。

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

Mybatis一级缓存

Mybatis的一级缓存原理sql

 

这里写图片描述

 

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

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

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

 

这里写图片描述

 

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

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

Mybatis二级缓存

二级缓存原理:缓存

 

这里写图片描述

 

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

 

这里写图片描述

 

Mybatis二级缓存配置

须要咱们在Mybatis的配置文件中配置二级缓存

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

上面已经说了,二级缓存的范围是mapper级别的,所以咱们的Mapper若是要使用二级缓存,还须要在对应的映射文件中配置..

<cache/>

查询结果映射的pojo序列化

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

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使用二级缓存。、、

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

刷新缓存

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

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

咱们在特定的状况下,还能够单独配置刷新缓存【但不建议使用】flushCache,默认是的true

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

了解Mybatis缓存的一些参数

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

flushInterval(刷新间隔)能够被设置为任意的正整数,并且它们表明一个合理的毫秒形式的时间段。默认状况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。
size(引用数目)能够被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值是1024。
readOnly(只读)属性能够被设置为true或false。只读的缓存会给全部调用者返回缓存对象的相同实例。所以这些对象不能被修改。这提供了很重要的性能优点。可读写的缓存会返回缓存对象的拷贝(经过序列化)。这会慢一些,可是安全,所以默认是false。

以下例子:
<cache  eviction="FIFO"  flushInterval="60000"  size="512"  readOnly="true"/>
这个更高级的配置建立了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,并且返回的对象被认为是只读的,所以在不一样线程中的调用者之间修改它们会致使冲突。可用的收回策略有, 默认的是 LRU:
1.LRU – 最近最少使用的:移除最长时间不被使用的对象。
2.FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
3.SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
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配置文件是配置全局的缓存管理方案

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
	<!--diskStore:缓存数据持久化的目录 地址  -->
	<diskStore path="F:\develop\ehcache" />
	<defaultCache 
		maxElementsInMemory="1000" 
		maxElementsOnDisk="10000000"
		eternal="false" 
		overflowToDisk="false" 
		diskPersistent="true"
		timeToIdleSeconds="120"
		timeToLiveSeconds="120" 
		diskExpiryThreadIntervalSeconds="120"
		memoryStoreEvictionPolicy="LRU">
	</defaultCache>
</ehcache>

若是咱们Mapper想单独拥有一些特性,须要在mapper.xml中单独配置

<!-- 单位:毫秒 -->
 	<cache type="org.mybatis.caches.ehcache.EhcacheCache">
 		<property name="timeToIdleSeconds" value="12000"/>
        <property name="timeToLiveSeconds" value="3600"/>
        <!-- 同ehcache参数maxElementsInMemory -->
		<property name="maxEntriesLocalHeap" value="1000"/>
		<!-- 同ehcache参数maxElementsOnDisk -->
        <property name="maxEntriesLocalDisk" value="10000000"/>
        <property name="memoryStoreEvictionPolicy" value="LRU"/>
 	</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)

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

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

public class StudentDao {

    public void add(Student student) throws Exception {
        //获得链接对象
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        try{
            //映射文件的命名空间.SQL片断的ID,就能够调用对应的映射文件中的SQL
            sqlSession.insert("StudentID.add", student);
            sqlSession.commit();
        }catch(Exception e){
            e.printStackTrace();
            sqlSession.rollback();
            throw e;
        }finally{
            MybatisUtil.closeSqlSession();
        }
    }
    public static void main(String[] args) throws Exception {
        StudentDao studentDao = new StudentDao();
        Student student = new Student(3, "zhong3", 10000D);
        studentDao.add(student);
    }
}

Mapper开发规范

想要Mybatis帮咱们自动生成Mapper代理的话,咱们须要遵循如下的规范:

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

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

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

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

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

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

Mapper代理返回值问题

mapper接口方法返回值:

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

Mybatis解决JDBC编程的问题

一、数据库连接建立、释放频繁形成系统资源浪费从而影响系统性能,若是使用数据库连接池可解决此问题。

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

二、Sql语句写在代码中形成代码不易维护,实际应用sql变化的可能较大,sql变更须要改变java代码。

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

三、向sql语句传参数麻烦,由于sql语句的where条件不必定,可能多也可能少,占位符须要和参数一一对应。

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

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

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

Mybatis逆向工程

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

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

借鉴博文:blog.csdn.net/for_my_life…

修改pom.xml文件

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

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>asdf</groupId>
    <artifactId>asdf</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <finalName>zhongfucheng</finalName>
        <plugins>
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.2</version>
                <configuration>
                    <verbose>true</verbose>
                    <overwrite>true</overwrite>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

generatorConfig.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>
    <!--
        <properties resource="conn.properties" />
          -->
    <!-- 处理1,这里的jar包位置可能须要修改 -->
    <classPathEntry location="C:\mybatisMaven\lib\mysql-connector-java-5.1.7-bin.jar"/>
    <!-- 指定运行环境是mybatis3的版本 -->
    <context id="testTables" targetRuntime="MyBatis3">

        <commentGenerator>
            <!-- 是否取消注释 -->
            <property name="suppressAllComments" value="true" />
            <!-- 是否生成注释代时间戳 -->
            <property name="suppressDate" value="true" />
        </commentGenerator>
        <!-- 处理2   jdbc 链接信息,看看库是否存在 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/scm?useUnicode=true&characterEncoding=UTF-8" userId="root" password="root">
        </jdbcConnection>

        <!--处理3   targetPackage指定模型在生成在哪一个包 ,targetProject指定项目的src,-->
        <javaModelGenerator targetPackage="zhongfucheng.entity"
                            targetProject="src/main/java">
            <!-- 去除字段先后空格 -->
            <property name="trimStrings" value="false" />
        </javaModelGenerator>
        <!--处理4   配置SQL映射文件生成信息 -->
        <sqlMapGenerator targetPackage="zhongfucheng.dao"
                         targetProject="src/main/java" />
        <!-- 处理5   配置dao接口生成信息-->
        <javaClientGenerator type="XMLMAPPER" targetPackage="zhongfucheng.dao" targetProject="src/main/java" />

        <table tableName="account" domainObjectName="Account"/>
        <table tableName="supplier" domainObjectName="Supplier"/>
    </context>
</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

相关文章
相关标签/搜索