• 【Hibernate框架】flush机制


    背景:

           一个偶然的机会,我做了一个例子,中间我遇到了一个有意思的问题,就是在执行commit方法之前,做了两次save操作,如下:

    1. SessionFactory sf = new Configuration().configure().buildSessionFactory() ;  
    2. Session s = sf.openSession();  
    3. Transaction tran = s.beginTransaction();  
    4. Animal animal1 = new Animal();  
    5. animal1 .setName(“tom”);  
    6. s.save(animal1 );  
    7.   
    8. animal1 .setName(“mary”);  
    9. s.update(animal1 );  
    10.   
    11. Animal animal2 = new Animal ();  
    12. animal2.setName(“tom”);  
    13. s.save(animal2);  
    14. tran.commit();  

    这样执行之后,报了一个:关于session主键冲突的异常,这之前,我也见过一个,就是整棵继承树映射一张表的时候,主键自增长不配置时,这个,我没有弄啊!然后开始这种查找资料,后来知道,commit方法会隐形的调用一个flush方法,而这个方法不是按照我们代码来提交事务的,而是会按着save、update、delete这个顺序来提交事务,所以会连续有两个save变成持久化对象,而造成session生成的Oid重复。

    也就是因为这个,我对flush感了兴趣,下面我们介绍一下关于flush的那些事:

    1、flush有什么用?

           调用flush方法,会按save,update,delete顺序执行,把缓存中的数据flush入数据库中,并清空缓存区;这里注意啊,这里只是将缓存中的数据同步到数据库中,这里并没有在数据库中insert数据,可以理解为把缓存内数据同步到一张临时表内(缓存区),这时候,直接查询数据库是没有新添数据的,但是使用发送sql语句查询却可以查出数据来(前提:数据库隔离级别要为 未提交读),当提交事务时,数据库事务管理器提交事务执行提交过来的sql语句,修改数据库数据。也就是说,只有commit才会更改数据库数据。

    整理一下啊:flush方法的主要作用就是清理缓存,强制数据库与hibernate缓存同步,以保证数据的一致性。其实在session持久化操作和数据库中之间还有一层对象缓冲区

    flush的主要动作就是向数据库发送一系列的sql语句,并执行这些sql语句,但是不会向数据库提交。而commit方法则会首先调用flush方法,然后提交事务。这就是为什么我们仅仅调用flush的时候记录并未插入到数据库中的原因,因为只有提交了事务,对数据库所做的更新才会被保存下来。因为commit方法隐式的调用了flush,所以一般我们都不会显示的调用flush方法。

    2、关于主键生成策略的一点隐私:

           当你的id主键生成策略为native,调用session.save后,将执行insert语句,返回有数据库生成的id 纳入了session的管理,修改了session中existsInDatabase状态为true,如果数据库的隔离级别设置为未提交读,那么我们可以看到save过的数据 ;

           当id主键生成策略采用的是uuid,调用完成save后,只是将user纳入到了session的管理,不会发出insert语句,但是id已经生成,session中existsInDatabase状态为false;

    3、最后那如何解决上面的问题呢,很简单,在update之后,执行session.flush,然后再第二个save之后,再执行一次flush就可以,

    1. SessionFactory sf = new Configuration().configure().buildSessionFactory() ;  
    2. Session s = sf.openSession();  
    3. Transaction tran = s.beginTransaction();  
    4. Animal animal1 = new Animal();  
    5. animal1 .setName(“tom”);  
    6. s.save(animal1 );  
    7.   
    8. animal1 .setName(“mary”);  
    9. s.update(animal1 );  
    10. s.flush();  
    11. Animal animal2 = new Animal ();  
    12. animal2.setName(“tom”);  
    13. s.save(animal2);  
    14. s.flush();  
    15. tran.commit();  

    这样就能按照我们的想法顺序缓存sql语句了有木有?

    4、总结:

           由于flush()的特殊处理机制,虽然不建议使用此方法,但是在一些复杂的事务处理过程中,加入此方法虽然会破坏事务的一个提交的完整性,但是可以规避一些不可预见的异常情况!

  • 相关阅读:
    [转]一致性hash算法
    [转]算法的时间复杂度和空间复杂度详解
    [转]B树(多向平衡查找树)详解
    spring中ApplicationContextAware接口描述
    [转]web.xml中<url-pattern>详解
    [转]linux中vim命令
    [转]Java GC的原理
    [转]浅谈UML的概念和模型之UML九种图
    Jmeter做读取csv接口测试
    IDLE崩溃:IDLE's subprocess didn't make connection. Either IDLE can't start a...
  • 原文地址:https://www.cnblogs.com/DoubleEggs/p/6248504.html
Copyright © 2020-2023  润新知