背景:

一个偶然的机会,我做了一个例子,中间我遇到了一个有意思的问题,就是在执行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. animal1 .setName(“mary”);
  8. s.update(animal1 );
  9. Animal animal2 = new Animal ();
  10. animal2.setName(“tom”);
  11. s.save(animal2);
  12. 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. animal1 .setName(“mary”);
  8. s.update(animal1 );
  9. s.flush();
  10. Animal animal2 = new Animal ();
  11. animal2.setName(“tom”);
  12. s.save(animal2);
  13. s.flush();
  14. tran.commit();

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

4、总结:

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

【Hibernate框架】flush机制的更多相关文章

  1. 从一次异常中浅谈Hibernate的flush机制

    摘自http://www.niwozhi.net/demo_c70_i1482.html http://blog.itpub.net/1586/viewspace-829613/ 这是在一次事务提交时 ...

  2. java框架篇---hibernate之缓存机制

    一.why(为什么要用Hibernate缓存?) Hibernate是一个持久层框架,经常访问物理数据库. 为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能. 缓存内的数据是对物理数 ...

  3. 深入浅出学习hibernate框架(三):java的反射机制

    上篇博客写到了JDBC的基本操作,今天准备写一篇关于JAVA反射机制的文章,因为java的反射机制和上一篇JDBC都是Hibernate框架的基本要素.在Hibernate的运行机制中,这两块的内容正 ...

  4. Hibernate框架—简介

    ORM对象/关系数据库映射 ORM全称Object/Relation Mapping,对象/关系数据库映射,可以理解成一种规范.该框架的基本特征:完成面向对象的编程语言到关系数据库之间的映射. ORM ...

  5. Hibernate框架的总结

    hibernate 简介:hibernate是一个开源框架,它是对象关联关系映射的框架,它对JDBC做了轻量级的封装,而我们java程序员可以使用面向对象的思想来操纵数据库.hibernate核心接口 ...

  6. J2EE进阶(八)Hibernate与延迟加载机制探究

    Hibernate与延迟加载机制探究 前言 Hibernate对象关系映射提供延迟的与非延迟的对象初始化.非延迟加载在读取一个对象的时候会将与这个对象所有相关的其他对象一起读取出来.这有时会导致成百的 ...

  7. hibernate框架学习之核心API

    ConfigurationSessionFactorySessionTransactionQueryCriteria Configuration Configuration对象用于封装Hibernat ...

  8. Hibernate框架第二天

    ### Hibernate的持久化类 ### ---------- **什么是持久化类** 1. 持久化类:就是一个Java类(咱们编写的JavaBean),这个Java类与表建立了映射关系就可以成为 ...

  9. Hibernate框架学习笔记

      Hibernate 是一个 JDO( Java Data Objects)工具.它的工作原理是通过文件把值对象(Java对象)和 数据库表之间建立起一个映射关系,还提供数据查询和获取数据的方法. ...

  10. Hibernate框架基本使用

    时间:2017-1-16 00:36 --什么是Hibernate    Hibernate是一个开放源代码的关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以使用对象编程思 ...

随机推荐

  1. JavaScript 秘密花园 学习心得

    目的 记录一下学习心得,便于以后复习,内容是比较基础的...但是很多内容我还是不知道... 对象 对象使用和属性 1.JavaScript 中所有变量都可以当作对象使用,除了两个例外 null和dun ...

  2. Node.js API 初解读(二)

    四. Cluster 1.简介 在介绍 Cluster 之前.我们需要知道 node的 一些基本特性,比如说 都知道的 nodejs最大的特点就是单进程.无阻塞运行,并且是异步事件驱动的. 那么随之而 ...

  3. Mysql基础(一)

    Mysql的历史度娘上一堆,就不再介绍了. 本文依照此路径学习Mysql数据库:数据库->表->数据 首先启动Mysql服务,然后通过控制台命令登入root账户输入密码回车 C:\User ...

  4. python 调用dll中c或c++语言的带指针方法,

    在项目开发中遇到了,python需要去调用一个动态链接库dll中的c++方法.这个方法的参数为一个指针类型的参数,一个bool类型参数, 在python中并未对数字类型进行区分. int LP_Agc ...

  5. 修改git remote url

    $ ssh -v wangz@gitlab.alibaxx-inc.com $ git remote ali set-url git@gitlab.alibaxx-inc.com:youk-aaa/x ...

  6. Unity NGUI添加UIRoot

    导入NGUI包后,菜单多出一个选项 "NGUI",选择其子选项 "options" -- "Reset Prefab ToolBar" ,在 ...

  7. Toast 工具

    public class Utils { private static Toast toast; public static void showtoast(Context context,String ...

  8. DNS解析过程详解

    先说一下DNS的几个基本概念: 一. 根域 就是所谓的“.”,其实我们的网址www.baidu.com在配置当中应该是www.baidu.com.(最后有一点),一般我们在浏览器里输入时会省略后面的点 ...

  9. Docker - 技术栈

    与传统的方式类似,构建及运行Docker容器与在一台虚拟机上构建和运行程序的方式是相似的,只是使用了一套新的工具以及技术. 与虚拟机不同的是,Docker容器将宿主机与应用程序或者服务隔离,从而提高了 ...

  10. [MySQL] 分页优化

    在传统的分页思路影响下,很多人都形成了对于分页的固定理解,也就是给出select语句,先用count()函数计算出总的条目,除与每个页面大小pagesize,然后用ceil取整,得出总的页数,用lim ...