hibernate对象的状态的理解(第五天)
2015-10-12 21:05
381 查看
昨天没有写,因为我感觉我对这块没有很明白,所以不能违背自己的理解,今天明白一些了,补上它。
hibernate中的对象分为三个状态,分别是瞬时状态,持久状态和离线状态。
瞬时状态:这个状态指的当前对象在session缓存中不存在,不受session管理,缓存中和数据库中没有相应的OID与当前对象对应。
持久状态:这个状态是指当前对象在缓存中有相应的引用指向他,并且有相应的OID与之对应;对于load方法来说在数据库中也存在(就这个地方我一直纠结,后面说)。
离线状态:对象还存在JVM中(session中没有引用,但是你对象本身没指向null),此时的对象不受session管理,本身来说和游离状态很相似,但其实离线对象是因为持久状态时session关闭了或者clear等操作而变成离线的,但是瞬时状态是持久状态delete后的,也就是说这两个之间的区别是一个在数据库中有OID一个没有OID。
网上找的图,贴上意思一下......
![](http://static.oschina.net/uploads/img/201510/12210514_UCay.jpg)
下面的代码来说明一下这三个状态:
这段代码最后能输出三条SQL 一条是查询当前最大主键(我的主键生成策略是increment,我对主键生成策略还没有完全理解就先不说这个),每次save都会执行所以不用关。然后是一条insert一条update。
在我们new一个对象(或者spring管理对象)的时候,这个对象是瞬时的,为什么说瞬时呢?我们一般初始化完一个对象就会将他持久化,所以我理解的瞬时就是这个状态应该会持续的时间短一点。
当我们执行save方法的时候,我们的对象就收到session的绑定了,但是庆大家一定注意:此时的对象只是在session缓存中有相应的OID对应,但是数据库中绝对没有这个对象(前提这个对象是全新的new出来的,而不是别的状态过去的)。我这么讲是因为我被很多资料和博客上的说法所迷惑,也许是我理解的比较极端,但是他们说的也是肯定不严谨。
有资料上会说:持久对象就是数据持久化在数据库和session缓存中的对象。我认为这句话前半句只对了“一种情况”,就是我们使用load的时候,首先load方法是hibernate从缓存中加载我们指定的ID的对象,要是没有的话就去数据库加载,那么资料上说的就是这个情况,使用loa从数据库加载对象这个步骤可以说,这时候的持久化对象是在数据库中的,但是save方法执行后的对象不能这么说,因为你事务没有提交的时候是不会操作数据库的,这是常识。
那么就会问了,insert语句到底怎么回事儿呢,我下面改了上面的代码,稍作修改,大家可以看看我是什么意思:
结果:
Hibernate: select max(id) from employee
5
Hibernate: insert into employee (name, email, hiredate, id) values (?, ?, ?, ?)
实际上执行了一个修改数据库的语句,是啊大家会问了,执行了一个save执行了三次修改对象的操作,为什么没有三次update呢?
这里,我就说出我的理解:我们在执行save,update,delete,merge以及修改对象的操作的时候,实际上会计划一条SQL语句,而不是执行,实际的执行在commit。这句话和结果有什么关系呢?正是因为实际操作数据库是commit,所以我们可以理解hibernate是这么做的,commit之前会比较session缓存中的对象和当前对象是不是一样的(反射机制吧),如果一样就不做操作,如果不一样就计划一条update语句。
也就是说,commit前面的操作对commit来说是透明的,commit并不知道你修改了几次对象。因为我代码最后,对象的名字改回来了,session缓存发现这个OID的对象和我当前对象的所有属性一样,所以就没有计划update语句。(这里特别注意,ID一般我们不会人为修改)
然后就是说一下第一张图的结果,执行一条insert和一条update,我的猜测是hibernate先执行插入,然后对比session中的值和对象的值,发现不一样,然后计划一条update语句并执行。实际上操作了两次数据库(而先前我认为hibernate应该会为了保证性能,尽量减少数据库操作,只在缓存中改完,然后一次性提交insert到数据库)。当然这只是我的猜测。
从持久状态到离线状态只需要session关闭或者清空,这时对象本身不是空,所以不会被JVM回收,而且还会和数据库中有对应的OID。
同样,如果我们修改了这个对象的属性(一般不要改ID),并update它们就会使其进入持久化状态。就好比一个被皇上贬到边疆的官员改过自新后,得到皇上重用再次回到皇宫差不多。如果这个时候使用delete就直接进入游离状态,好比直接被皇上贬成草民了,想要回到皇宫就只能再进京赶考(在执行save)差不多。
我说的可能有点不太对,而且里面有部分是我的猜测(比如commit的时候到底操作了几次数据库),如果不对,请大家指正,初学hibernate,如果说的是对的那我表示很荣幸;如果理解的有问题,还是希望立马改过来的。
版权声明:本文为博主原创文章,未经博主允许不得转载。
hibernate中的对象分为三个状态,分别是瞬时状态,持久状态和离线状态。
瞬时状态:这个状态指的当前对象在session缓存中不存在,不受session管理,缓存中和数据库中没有相应的OID与当前对象对应。
持久状态:这个状态是指当前对象在缓存中有相应的引用指向他,并且有相应的OID与之对应;对于load方法来说在数据库中也存在(就这个地方我一直纠结,后面说)。
离线状态:对象还存在JVM中(session中没有引用,但是你对象本身没指向null),此时的对象不受session管理,本身来说和游离状态很相似,但其实离线对象是因为持久状态时session关闭了或者clear等操作而变成离线的,但是瞬时状态是持久状态delete后的,也就是说这两个之间的区别是一个在数据库中有OID一个没有OID。
网上找的图,贴上意思一下......
![](http://static.oschina.net/uploads/img/201510/12210514_UCay.jpg)
下面的代码来说明一下这三个状态:
public static void main(String[] args) { // TODO Auto-generated method stub Session session = HibernateUtil.openSession(); Transaction trans = null; try { trans = session.beginTransaction(); Employee employee1 = new Employee("feizhu","cc@qq.com",new Date());//这时对象是瞬时状态 session.save(employee1);//这时对象变成持久状态,受session管理。 System.out.println(employee1.getId()); employee1.setName("lua"); trans.commit(); } catch (Exception e) { // TODO Auto-generated catch block if(trans!=null) trans.rollback(); e.printStackTrace(); }finally{ if(session!=null||session.isOpen()) session.close(); //session关闭,对象变成离线状态。 } } }
这段代码最后能输出三条SQL 一条是查询当前最大主键(我的主键生成策略是increment,我对主键生成策略还没有完全理解就先不说这个),每次save都会执行所以不用关。然后是一条insert一条update。
在我们new一个对象(或者spring管理对象)的时候,这个对象是瞬时的,为什么说瞬时呢?我们一般初始化完一个对象就会将他持久化,所以我理解的瞬时就是这个状态应该会持续的时间短一点。
当我们执行save方法的时候,我们的对象就收到session的绑定了,但是庆大家一定注意:此时的对象只是在session缓存中有相应的OID对应,但是数据库中绝对没有这个对象(前提这个对象是全新的new出来的,而不是别的状态过去的)。我这么讲是因为我被很多资料和博客上的说法所迷惑,也许是我理解的比较极端,但是他们说的也是肯定不严谨。
有资料上会说:持久对象就是数据持久化在数据库和session缓存中的对象。我认为这句话前半句只对了“一种情况”,就是我们使用load的时候,首先load方法是hibernate从缓存中加载我们指定的ID的对象,要是没有的话就去数据库加载,那么资料上说的就是这个情况,使用loa从数据库加载对象这个步骤可以说,这时候的持久化对象是在数据库中的,但是save方法执行后的对象不能这么说,因为你事务没有提交的时候是不会操作数据库的,这是常识。
那么就会问了,insert语句到底怎么回事儿呢,我下面改了上面的代码,稍作修改,大家可以看看我是什么意思:
try { trans = session.beginTransaction(); Employee employee1 = new Employee("feizhu","cc@qq.com",new Date()); <span style="color:#ff0000;">session.save(employee1); System.out.println(employee1.getId()); employee1.setName("lua"); employee1.setName("java"); employee1.setName("feizhu"); trans.commit();</span> } catch (Exception e) { // TODO Auto-generated catch block if(trans!=null) trans.rollback(); e.printStackTrace(); }finally{ if(session!=null||session.isOpen()) session.close(); }我在save之后修改了三次employee1对象的name,那么你们觉得最后会打印几条SQL呢?
结果:
Hibernate: select max(id) from employee
5
Hibernate: insert into employee (name, email, hiredate, id) values (?, ?, ?, ?)
实际上执行了一个修改数据库的语句,是啊大家会问了,执行了一个save执行了三次修改对象的操作,为什么没有三次update呢?
这里,我就说出我的理解:我们在执行save,update,delete,merge以及修改对象的操作的时候,实际上会计划一条SQL语句,而不是执行,实际的执行在commit。这句话和结果有什么关系呢?正是因为实际操作数据库是commit,所以我们可以理解hibernate是这么做的,commit之前会比较session缓存中的对象和当前对象是不是一样的(反射机制吧),如果一样就不做操作,如果不一样就计划一条update语句。
也就是说,commit前面的操作对commit来说是透明的,commit并不知道你修改了几次对象。因为我代码最后,对象的名字改回来了,session缓存发现这个OID的对象和我当前对象的所有属性一样,所以就没有计划update语句。(这里特别注意,ID一般我们不会人为修改)
然后就是说一下第一张图的结果,执行一条insert和一条update,我的猜测是hibernate先执行插入,然后对比session中的值和对象的值,发现不一样,然后计划一条update语句并执行。实际上操作了两次数据库(而先前我认为hibernate应该会为了保证性能,尽量减少数据库操作,只在缓存中改完,然后一次性提交insert到数据库)。当然这只是我的猜测。
从持久状态到离线状态只需要session关闭或者清空,这时对象本身不是空,所以不会被JVM回收,而且还会和数据库中有对应的OID。
同样,如果我们修改了这个对象的属性(一般不要改ID),并update它们就会使其进入持久化状态。就好比一个被皇上贬到边疆的官员改过自新后,得到皇上重用再次回到皇宫差不多。如果这个时候使用delete就直接进入游离状态,好比直接被皇上贬成草民了,想要回到皇宫就只能再进京赶考(在执行save)差不多。
我说的可能有点不太对,而且里面有部分是我的猜测(比如commit的时候到底操作了几次数据库),如果不对,请大家指正,初学hibernate,如果说的是对的那我表示很荣幸;如果理解的有问题,还是希望立马改过来的。
版权声明:本文为博主原创文章,未经博主允许不得转载。
相关文章推荐
- Oracle Containers for J2EE远程安全漏洞(CVE-2014-0413)
- Hibernate Oracle sequence的使用技巧
- jsp Hibernate批量更新和批量删除处理代码
- jsp hibernate的分页代码第1/3页
- JAVA+Hibernate 无限级分类
- SSH整合中 hibernate托管给Spring得到SessionFactory
- jsp hibernate 数据保存操作的原理
- hibernate中的增删改查实现代码
- 解决hibernate+mysql写入数据库乱码
- java优化hibernate性能的几点建议
- java Hibernate延迟加载
- hibernate 常用方法介绍
- 深入理解Hibernate中的flush机制
- 简单的手工hibernate程序示例
- J2EE项目代码编写规范分享
- 解析使用jdbc,hibernate处理clob/blob字段的详解
- 浅析java程序中hibernate的应用总结
- java面试常见问题之Hibernate总结
- 关于Hibernate的一些学习心得总结
- JDK、J2EE、J2SE、J2ME四个易混淆概念区分