• FlushMode属性与transaction(spring注入的事务)


    一、参见hibernate的api

    http://tool.oschina.net/apidocs/apidoc?api=hibernate-3.6.10

    http://tool.oschina.net/apidocs/apidoc?api=hibernate-4.1.4

    说明:贴出两个版本的原因在于FlushMode属性在3.6与4.1版本的设置有所不同,3.6的FlushMode属性是一个Class类,而4.1已更换了Enum。

    二、 FlushMode属性(策略)

    在org.hibernate Class FlushMode中这样解释它的作用:Represents a flushing strategy. The flush process synchronizes database state with session state by detecting state changes and executing SQL statements.

    代表一个flushing(刷新)的策略,它将通过改变session的状态和执行SQL的状态来处理线程中的数据。 

    NEVER 已被MANUAL取代

    ALWAYS在查询前刷新Session

    AUTO 在确保查询从不会返回脏数据的情况下,在查询前刷新Session

    COMMITSession在提交事务时刷新。

    MANUALSession永远只会在应用程序调用Session.flush()方法时才会刷新。

    说明:

    1. Session:Session接口是Hibernate向程序提供操纵数据库的最主要接口,是单线程对象,它提供了基本的保存、更新、删除和查询方法。它有一个缓存,保存了持久化对象,当清理缓存时,按照这些持久化对象同步更新数据库。根据Session的定义,可以知道刷新Session也就刷新了数据库。

    2.调用Session.flush()方法,不管FlushMode被设置成任何策略,均会将刷新Session,使其中的缓存数据同步至数据库。

    3.ALWAYSAUTO的区别:从API看出,AUTO的解释Session刷新较ALWAYS多了一个“sometimes ”,说明AUTO并不会像ALWAYS那样总是刷新Session,那它在何时才会刷新呢?当hibernate缓存中的对象被改动之后,会被标记为脏数据(即与数据库不同步了)。当 session设置为FlushMode.AUTO时,hibernate在进行查询的时候会判断缓存中的数据是否为脏数据,是则刷数据库,不是则不刷,而always是直接刷新,不进行任何判断。很显然auto比always要高效得多。

    4.设置FlushMode.MANUAL,在操作过程中hibernate会将事务设置为readonly,所以在增加、删除或修改操作过程中会出现如下错误:

    org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.

     解决方式见“附:解决因FlushMode设置出现不能进行增、删、改的异常”

    用表格形式表示如下:

    表1

    Session的刷新策略

    调用Session的查询方法时

    调用Session.commit()时

    调用Session.flush()时

    ALWAYS

    刷新

    刷新

    刷新

    AUTO

    当缓存被标记为脏数据时,刷新

    刷新

    刷新

    COMMIT

    不刷新

    刷新

    刷新

    MANUAL

    不刷新

    不刷新

    刷新

    三、小结:FlushMode的4个属性实际上代表了Hibernate处理Session中的持久化对象的缓存的4种策略,这4种策略最大的不同就是刷新Session,将其中的缓存的持久化对象同步更新数据库的时间点不同。

    四、OpenSessionInViewFilter的FlushMode属性设置与transaction(spring注入的事务)的关系:假设在OpenSessionInViewFilter设置FlushMode.MANUAL若OpenSessionInViewFilter在getSession的时候,会把获取回来的session的flush mode 设为FlushMode.MANUAL。然后把该sessionFactory绑定到TransactionSynchronizationManager,使request的整个过程都使用同一个session,在请求过后再解除该sessionFactory的绑定,最后closeSessionIfNecessary根据该session是否已和transaction绑定来决定是否关闭session。在这个过程中,若HibernateTemplate 发现自当前session有不是readOnly的transaction,就会获取到FlushMode.AUTO Session,使方法拥有写权限。也即是,如果有不是readOnly的transaction就可以由Flush.NEVER转为Flush.AUTO,拥有insert,update,delete操作权限,如果没有transaction,并且没有另外人为地设flush model的话,则doFilter的整个过程都是Flush.MANUAL。所以受transaction保护的方法有写权限,没受保护的则没有。

    附:解决因FlushMode设置出现不能进行增、删、改的异常

    1.配置事务,spring会读取事务中的各种配置来覆盖hibernate的session中的FlushMode。此种情况下,即使在FlushMode设置MANUAL也没有关系(这并意味OpenSessionInViewFilter的FlushMode属性可以随意设置,这得依据实际需求,具体参见第四点--OpenSessionInViewFilter的FlushMode属性设置与transaction(spring注入的事务)的关系)。

    例:

    <bean id="txManager"
            class="org.springframework.orm.hibernate3.HibernateTransactionManager">
            <property name="sessionFactory" ref="sessionFactory" />
        </bean>
        <aop:config>
            <aop:pointcut id="managerOperation"
                expression="execution(* com.test.service.*.*(..))"/>
            <aop:advisor advice-ref="txAdvice" pointcut-ref="managerOperation" />
        </aop:config>
        <tx:advice id="txAdvice" transaction-manager="txManager">
            <tx:attributes>
                <tx:method name="*"  propagation="REQUIRED" read-only="true" />
                <tx:method name="save*" propagation="REQUIRED" />
                <tx:method name="add*"  propagation="REQUIRED" />
                <tx:method name="del*"  propagation="REQUIRED" />
                <tx:method name="update*" propagation="REQUIRED" isolation="REPEATABLE_READ"/>
            </tx:attributes>
        </tx:advice>  
    2.直接修改opensessioninviewfilter过滤器的配置,配置过滤器的时候置 openSession org.springframework.orm.hibernate3.support.OpenSessionInViewFilter中 flushMode为AUTO/COMMIT 。注意:如果这样设置,则要么结合1,要么结合3,因为不管怎样,对于Hibernate来说总是要配置事务,否则无法操作持久化对象同步至数据库。

    例:

    <filter>
            <filter-name>openSessionInViewFilter</filter-name>
            <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
            <init-param>
                <param-name>singleSession</param-name>
                <param-value>true</param-value>
            </init-param>
            <init-param>
                <param-name>flushMode</param-name>
                <param-value>AUTO</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>openSessionInViewFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>

    3.先编程式修改FlushMode,比如session.setFlushMode(FlushMode.AUTO); 

    例:

    @Override
        public void saveOrUpdate(T t) {
            Session session = null;
            Transaction tr = null;
            try {
                session = HibernateSessionFactory.getSession();
                tr = session.beginTransaction();
                session.saveOrUpdate(t);
                tr.commit();
                HibernateSessionFactory.closeSesssion();
            } catch (Exception e) {
                e.printStackTrace();
                tr.rollback();
            }
        }

    鸣谢:http://blog.csdn.net/accpsz/article/details/6010618

    http://blog.csdn.net/looyo/article/details/6309136

  • 相关阅读:
    电位器的使用
    序言
    跨域之options请求详解
    redis config 实现切库 和指定序列化
    巨坑! druid1.1.0
    跨域问题解决
    canal解决缓存穿透 对数据库同步数据至redis 或EleasticSearch
    oauth2+spring security +jwt 完成分布式服务认证
    oauth2的数据库设计
    Gson 转换 Localdate 使用 GsonBuilder setDateFormat 无效
  • 原文地址:https://www.cnblogs.com/wql025/p/4822791.html
Copyright © 2020-2023  润新知