关于Hibernate与spring集成更新无效的分析

来源:互联网 发布:手机淘宝代付在哪里 编辑:程序博客网 时间:2024/05/19 14:51
         刚开始写博客,其中有何纰漏请包涵一二。

    Hibernate是一个ORM持久化框架,也是主流的ORM框架之一。使用它,程序员能够利用OOP思想操作数据库数据。但是新手刚开始学习Hibernate的时候,由于对于Hibernate的工作原理和机制理解不透彻,在使用过程中,将会遇到许多问题和掉入许多深坑(好几天出不来,比如楼主我,唉~~~~),大大的降低了工作效率。最近使用Hibernte做个人项目时,又掉进了深坑,为了避免更多小白入坑难以自拔,就有了楼楼这篇漏作。
    在使用Hibernate的时候,使用框架的接口方法,能够简化开发代码,楼楼在做个人项目时为了省点时间撸,就想尝试使用Hibernate的接口方法,像什么save()、delete()、update()、saveorUpdate()的,不过确实很方便。在使用过程中就遇到问题,就行update()更新无效,数据更新不完全等等。
    一、 使用Update更新数据无效。
    在调用update方法更新数据时,更新操作无效,也不抛出任何异常。楼楼复习了hibernate知识和查阅了相关资料,并经过了自身测试,找到了问题所在。
    在使用Hibernate与spring集成时,将Hibernate事务交给spring管理。配置文件如:

    
   
 <!-- 定义事务 -->    <bean id="transactionManager"        class="org.springframework.orm.hibernate4.HibernateTransactionManager">        <property name="sessionFactory" ref="sessionFactory" />    </bean>    <tx:advice id="txAdvice" transaction-manager="transactionManager">        <!-- 配置详细的事务定义 -->        <tx:attributes>            <!-- 所有以查询数据库的方法是read-only的 -->            <tx:method name="get*" propagation="REQUIRED" read-only="true" />            <tx:method name="find*" propagation="REQUIRED" read-only="true" />            <tx:method name="list*" propagation="REQUIRED" read-only="true" />            <!-- 其他方法使用默认的事务设置 -->            <tx:method name="add*" propagation="REQUIRED" />            <tx:method name="save*" propagation="REQUIRED" />            <tx:method name="del*" propagation="REQUIRED" />            <tx:method name="update*" propagation="REQUIRED" />        </tx:attributes>    </tx:advice>    <aop:config>        <aop:pointcut expression="execution(* com.hal.bms..*.services..*.*Services.*(..))"            id="allpoint" />        <aop:advisor advice-ref="txAdvice" pointcut-ref="allpoint" />    </aop:config>


在配置文件中,配置了事务管理的,其他方法调用不存在任何问题,但是update方法却出了问题。也就是说并不是spring事务管理的事。

    情况一:

    在使用update的时候,更新的是缓存中的数据,并不会立马同步到数据库中,如果想立即更新数据库数据,就可以使用session.flush()方法。我们来测试一下吧:
        测试代码:
    
        public  void  updateSelf(User user){
      System.out.println("进入本方法!");
      getSession().update(user);
      getSession().flush();
 }

         注意图片中的第四条数据,待会就是测试这条了。


     

        然后将用户的地址改为“中国北京”,看看测试结果。

测试成功。说明更新无效是由于只更新了缓存中的数据,如果不调用flush,则数据库并不会更新。

能成功的前提是因为在web.xml配置了OSIV

<!-- Hibeinate OSIV 配置 --><filter><filter-name>OpenSessionInViewFilter</filter-name><filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>        <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>

  情况二:

   就是情况一下面要说的FlushMode属性,该属性有五中状态(这个网上一查就知道了),分别是:

1、NEVEL:被MANUAL取代了 
2 MANUAL: 
如果FlushMode是MANUAL或NEVEL,在操作过程中hibernate会将事务设置为readonly,所以在增加、删除或修改操作过程中会出现如下错误 
org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session into FlushMode.AUTO or remove 'readOnly' marker from transaction definition; 
解决办法:配置事务,spring会读取事务中的各种配置来覆盖hibernate的session中的FlushMode; 
3 AUTO 
设置成auto之后,当程序进行查询、提交事务或者调用session.flush()的时候,都会使缓存和数据库进行同步,也就是刷新数据库 
4 COMMIT 
提交事务或者session.flush()时,刷新数据库;查询不刷新 
5 ALWAYS: 
每次进行查询、提交事务、session.flush()的时候都会刷数据库 
ALWAYS和AUTO的区别:当hibernate缓存中的对象被改动之后,会被标记为脏数据(即与数据库不同步了)。当 session设置为FlushMode.AUTO时,hibernate在进行查询的时候会判断缓存中的数据是否为脏数据,是则刷数据库,不是则不刷,而always是直接刷新,不进行任何判断。很显然auto比always要高效得多。


所以如果没有配置OSIV,就需要自己手动设置FlushMode属性:session.setFlushMode(FlushMode.xxx)。


情况三:就是事务并没有管理update的类或方法,这时就需要自己手动添加事务管理。在方法上添加事务注解属性@Transactional。然后参考情况一二。


以上属个人对于Hibernate的理解,如有偏差,还望指正。





 

   


       
         
       
 

0 0