zoukankan      html  css  js  c++  java
  • (四)mybatis缓存、事务、插件的基本知识

    mybatis缓存、事务、插件的基础

    一、缓存

    (一)一级缓存与二级缓存

      一级缓存

      为了获得更好的性能,最重要的就是一级缓存。每个session对象维持一个一级缓存,session对象创建时缓存创建,session对象释放时缓存销毁。

      缓存是一个哈希表。哈希表根据唯一键存储值,值可以根据唯一键检索。一个实体由它的ID唯一标识,如果两个实体类型相同,ID也相等,那么这两个实体是相等的。

       session对象从数据库中加载指定ID的实体,然后放到一级缓存中,访问该实体的键是它的ID值。当系统再次从数据库中加载同一个实体时,session对象首先检查它的缓存,如果实体已经存在于缓存中,就返回缓存的实例。只有实体不在缓存时,session对象才从数据库中加载实体。

      二级缓存

      一级缓存绑定到session对象,也就是说每次session被释放,所有的缓存数据就会丢失。

      二级缓存定义在session工厂级别的,只要session工厂没有被释放缓存就一直存在。一旦实体加载,二级缓存就被激活,实体对所有的session(同session工厂的)都可用。这样,只要实体在二级缓存中,对象就不会从数据库加载实体,直到它从缓存中移除。

    (二)mybatis缓存

      mybatis默认开启一级缓存,即一个缓存相对于同一个SqlSession而言。使用同一个session查询时,mybatis会将其放在缓存中,以后再查询时,如果没有声明需要刷新,在缓存未超时的情况下,SQLSession都只会取出当前缓存数据。若使用不同的SQLSession对象,调用相同的mapper、参数和方法,均需要到数据库执行。

      二级缓存的开启需要配置,并且要求返回的POJO是可序列化的,即实体类实现Serializable接口;在映射XML文件配置<cache/>就可以开启缓存了。

      详细配置:<cache eviction="LRU" flushInterval="100000" size="1024" readOnly="true"/>

        eviction:缓存回收策略

          1.LRU,最近最少使用的,移除最长时间不用的对象

          2.FIFO,先进先出,按对象进入缓存的顺序来移除

          3.SOFT,软引用,移除基于垃圾回收器状态和软引用规则的对象

          4.WEAK,弱引用,更积极地移除基于垃圾收集器状态和弱引用规则的对象。

        flushInterval:刷新时间间隔,单位毫秒,默认SQL被执行时刷新

        size:引用数目,最大存储对象数目

        readOnly:只读,意味着缓存数据只能读取而不能修改。优点:可以快速读取缓存。缺点:没办法修改缓存,默认值为false

      自定义缓存

        1.实现org.apache.ibatis.cache.Cache接口

        2.配置自定义缓存:<cache type="自定义cache实现类"/>

        3.(可选)设置自定义缓存参数

          <cache type="">

            <property name="host" value="localhost"/>

          </cache>

        4.(可选)映射器上可以配置缓存规则

          eg. <select ... flushCache="flase" useCache="true"/>

    二、事务

    (一)spring事务管理

      spring事务管理是通过springAOP实现的。

      1.事务传播机制(propagation)

        (1)REQUIRED:如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。

        (2)SUPPORTS: 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。但是对于事务同步的事务管理器,PROPAGATION_SUPPORTS与不使用事务有少许不同。

        (3)NOT_SUPPORTED:总是非事务地执行,并挂起任何存在的事务。

        (4)REQUIRESNEW:总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。

        (5)MANDATORY:如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。

        (6)NEVER:总是非事务地执行,如果存在一个活动事务,则抛出异常

        (7)NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。

      2.事务隔离级别

        ISOLATION_DEFAULT: 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.

      另外四个与JDBC的隔离级别相对应:

        (1)ISOLATION_READ_UNCOMMITTED: 这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。

        (2)ISOLATION_READ_COMMITTED: 保证一个事务修改的数据提交后才能被另一个事务读取。

        (3)ISOLATION_REPEATABLE_READ: 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。

        (4)ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。

    (二)mybatis和spring整合管理事务(使用springAOP)

      applicationContext.xml配置

    1 <!--  配置jdbc事务管理器,完成数据的完整性和一致性 -->
    2     <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    3         <property name="dataSource" ref="dataSource"></property>
    4     </bean>
    5     <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>

      使用注解方式添加事务:

      @Transactional(value="transactionManager",propagation=Propagation.REQUIRES_NEW,isolation=Isolation.READ_COMMITTED)

    属性

    类型

    描述

    value String

    可选的限定描述符,指定使用的事务管理器

    propagation

    enum: Propagation

    可选的事务传播行为设置

    isolation

    enum: Isolation

    可选的事务隔离级别设置

    readOnly

    boolean

    读写或只读事务,默认读写

    timeout

    int (in seconds granularity)

    事务超时时间设置

    rollbackFor

    Class对象数组,必须继承自Throwable

    导致事务回滚的异常类数组

    rollbackForClassName

    类名数组,必须继承自Throwable

    导致事务回滚的异常类名字数组

    noRollbackFor

    Class对象数组,必须继承自Throwable

    不会导致事务回滚的异常类数组

    noRollbackForClassName

    类名数组,必须继承自Throwable

    不会导致事务回滚的异常类名字数组


      注意:

      1.在需要事务管理的地方加@Transactional 注解。@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。

      2.通过元素的 “proxy-target-class” 属性值来控制是基于接口的还是基于类的代理被创建。如果 “proxy-target-class” 属值被设置为 “true”,那么基于类的代理将起作用(这时需要CGLIB库cglib.jar在CLASSPATH中)。如果 “proxy-target-class” 属值被设置为 “false” 或者这个属性被省略,那么标准的JDK基于接口的代理将起作用。

      3.Spring团队建议在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。在接口上使用 @Transactional 注解,只能当你设置了基于接口的代理时它才生效。因为注解是 不能继承 的,这就意味着如果正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装。

      4.@Transactional 的事务开启,或者是基于接口的或者是基于类的代理被创建。所以在同一个类中一个方法调用另一个方法有事务的方法,事务是不会起作用的。

    三、插件

      使用插件会修改mybatis的底层封装,需要去掌握mybatis的四大对象协作过程和插件的实现原理

       插件开发过程:

        1.确定需要拦截的签名:

          确定要拦截的对象:Executor、StatementHandler、ParameterHandler、ResultHandler;

          拦截方法和参数;

        eg.拦截修改需要执行的SQL语句

    1 @Intercepts({@Signature(
    2         type=StatementHandler.class,
    3         method="prepare",
    4         args={Connection.class,Integer.class}
    5         )})
    6 public class MyPlugin implements Interceptor{
    7   ...      
    8 }

        @Intercepts 说明它是拦截器

        @Signature 注册拦截器签名的地方:

          type:是四大对象中的一个

          method:要拦截四大对象的某一种接口方法

          args:表示该参数的方法

        2.实现拦截方法

     1 @Intercepts({@Signature(
     2                 type=StatementHandler.class,
     3                 method="prepare",
     4                 args={Connection.class,Integer.class}
     5                 )})
     6 public class MyPlugin implements Interceptor{
     7     Properties props=null;
     8     @Override
     9     public Object intercept(Invocation invocation) throws Throwable {
    10         //如果当前代理的是一个非代理对象,那么它就会调用真实拦截对象的方法,若不是它会调用下个插件代理对象的invoke方法
    11         Object obj=invocation.proceed();
    12         return obj;
    13     }
    14 
    15     /*
    16      * 生成对象的代理,这里常用Mybatis提供的Plugin类的wrap方法
    17      * target:被代理的对象
    18      */
    19     @Override
    20     public Object plugin(Object target) {
    21         //使用mybatis提供的plugin类生成代理对象
    22         return Plugin.wrap(target,this);
    23     }
    24 
    25     /*
    26      * 获取插件配置的属性,我们在mybatis的配置文件里去配置
    27      */
    28     @Override
    29     public void setProperties(Properties properties) {
    30         // TODO Auto-generated method stub
    31         this.props=properties;
    32     }
    33 }

        3.配置和运行

    <plugins>
        <plugin interceptor="xxx.MyPlugin">
            <property name="dbType" value="derby"/>
        </plugin>
    </plugins>    

     

  • 相关阅读:
    CRM更新行数量汇总的一些注意点
    [转]IT人从业方向
    地球撞击
    如何将Dynamic CRM Activities添加到VS工具箱
    linux本地 yum环境建立
    【转】根据条件修改GridView命令按钮显示的文字
    【转】Asp.net 2.0三层架构的构建与理解
    GridView的常用用法总结说明
    IE中的奇怪问题
    解决打不开 RSA 密钥容器 即:加密web.config中的内容
  • 原文地址:https://www.cnblogs.com/zuzZ/p/8107909.html
Copyright © 2011-2022 走看看