`
王牌海盗
  • 浏览: 238628 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Hibernate中主键unsave-value属性的用法

阅读更多
当你显式的使用session.save()或者session.update()操作一个对象的时候,实际上是用不到unsaved-value 的。某些情况下(父子表关联保存),当你在程序中并没有显式的使用save或者update一个持久对象,那么Hibernate需要判断被操作的对象究竟是一个已经持久化过的持久对象,是一个尚未被持久化过的内存临时对象。例如:
代码
1. Session session = ...;  
2. Transaction tx = ...;  
3.  
4. Parent parent = (Parent) session.load(Parent.class, id);  
5.  
6. Child child = new Child();  
7. child.setParent(parent);  
8. child.setName("sun");  
9.  
10. parent.addChild(child);  
11. s.update(parent);  
12.  
13. s.flush();  
14. tx.commit();  
15. s.close(); 
在上例中,程序并没有显式的session.save(child); 那么Hibernate需要知道child究竟是一个临时对象,还是已经在数据库中有的持久对象。如果child是一个新创建的临时对象(本例中就是这种情况),那么Hibernate应该自动产生session.save(child)这样的操作,如果child是已经在数据库中有的持久对象,那么 Hibernate应该自动产生session.update(child)这样的操作。
因此我们需要暗示一下Hibernate,究竟child对象应该对它自动save还是update。在上例中,显然我们应该暗示Hibernate对 child自动save,而不是自动update。那么Hibernate如何判断究竟对child是save还是update呢?它会取一下child 的主键属性 child.getId() ,这里假设id是 java.lang.Integer类型的。如果取到的Id值和hbm映射文件中指定的unsave-value相等,那么Hibernate认为 child是新的内存临时对象,发送save,如果不相等,那么Hibernate认为child是已经持久过的对象,发送update。
unsaved-value="null" (默认情况,适用于大多数对象类型主键 Integer/Long/String/...)
当Hibernate取一下child的Id,取出来的是null(在上例中肯定取出来的是null),和unsaved-value设定值相等,发送save(child)
当Hibernate取一下child的id,取出来的不是null,那么和unsaved-value设定值不相等,发送update(child)
例如下面的情况:
代码
1. Session session = ...;  
2. Transaction tx = ...;  
3.  
4. Parent parent = (Parent) session.load(Parent.class, id);  
5. Child child = (Child) session.load(Child.class, childId);  
6.  
7. child.setParent(parent);  
8. child.setName("sun");  
9.  
10. parent.addChild(child);  
11. s.update(parent);  
12.  
13. s.flush();  
14. tx.commit();  
15. s.close(); 
child已经在数据库中有了,是一个持久化的对象,不是新创建的,因此我们希望Hibernate发送update(child),在该例中,Hibernate取一下child.getId(),和unsave-value指定的null比对一下,发现不相等,那么发送 update(child)。
BTW: parent对象不需要操心,因为程序显式的对parent有load操作和update的操作,不需要Hibernate自己来判断究竟是save还是 update了。我们要注意的只是child对象的操作。另外unsaved-value是定义在Child类的主键属性中的。
代码
1. <class name="Child" table="child"> 
2. <id column="id" name="id" type="integer" unsaved-value="null"> 
3.    <generator class="identity"/> 
4. </id> 
5. ...  
6. </class> 
如果主键属性不是对象型,而是基本类型,如int/long/double/...,那么你需要指定一个数值型的unsaved-value,例如:

代码
1. unsaved-null="0" 
在此提醒大家,很多人以为对主键属性定义为int/long,比定义为Integer/Long运行效率来得高,认为基本类型不需要进行对象的封装和解构操作,因此喜欢把主键定义为int/long的。但实际上,Hibernate内部总是把主键转换为对象型进行操作的,就算你定义为int/long型的,Hibernate内部也要进行一次对象构造操作,返回给你的时候,还要进行解构操作,效率可能反而低也说不定。因此大家一定要扭转一个观点,在 Hibernate中,主键属性定义为基本类型,并不能够比定义为对象型效率来的高,而且也多了很多麻烦,因此建议大家使用对象型的 Integer/Long定义主键
unsaved-value="none"和
unsaved-value="any"
主主要用在主键属性不是通过Hibernate生成,而是程序自己setId()的时候。
在这里多说一句,强烈建议使用Hibernate的id generator,或者你可以自己扩展Hibernate的id generator,特别注意不要使用有实际含义的字段当做主键来用!例如用户类User,很多人喜欢用用户登陆名称做为主键,这是一个很不好的习惯,当用户类和其他实体类有关联关系的时候,万一你需要修改用户登陆名称,一改就需要改好几张表中的数据。偶合性太高,而如果你使用无业务意义的id generator,那么修改用户名称,就只修改user表就行了。
由这个问题引申出来,如果你严格按照这个原则来设计数据库,那么你基本上是用不到手工来setId()的,你用Hibernate的id generator就OK了。因此你也不需要了解当
unsaved-value="none"和
unsaved-value="any"
究竟有什么含义了。如果你非要用assigned不可,那么继续解释一下:
unsaved-value="none" 的时候,由于不论主键属性为任何值,都不可能为none,因此Hibernate总是对child对象发送update(child)
unsaved-value="any" 的时候,由于不论主键属性为任何值,都肯定为any,因此Hibernate总是对child对象发送save(child)
大多数情况下,你可以避免使用assigned,只有当你使用复合主键的时候不得不手工setId(),这时候需要你自己考虑究竟怎么设置unsaved-value了,根据你自己的需要来定。
BTW: Gavin King强烈不建议使用composite-id,强烈建议使用UserType。
因此,如果你在系统设计的时候,遵循如下原则:
1、使用Hibernate的id generator来生成无业务意义的主键,不使用有业务含义的字段做主键,不使用assigned。
2、使用对象类型(String/Integer/Long/...)来做主键,而不使用基础类型(int/long/...)做主键
3、不使用composite-id来处理复合主键的情况,而使用UserType来处理该种情况。
那么你永远用的是unsaved-value="null" ,不可能用到any/none/..了。
分享到:
评论

相关推荐

    unsave-changes-detector:检测JavaScript属性更改并返回布尔值

    unsave-changes-detector也具有相同的功能,但是试图使开发人员更容易安装通过npm可以使用unsave-changes-detector: npm install unsave-changes-detector --save例子const UnsaveChangesDetector = require ( '...

    NHibernate配置的过程.pdf

    - **unsave-value设置**:对于实体类映射文件中的`unsave-value`属性的具体设置,请参考作者在CSDN博客中的文章。 ##### 4. NHibernate配置文件设置 - **配置文件模板**:在NHibernate安装包的`Configuration_...

    C#基础与语法

    - B项描述错误,使用方法隐藏时,`new`关键字是必须的。 - C项描述正确。 - D项描述正确。 #### 二、简单题解析及知识点说明 **1. string和stringBuilder的区别** - **知识点说明:** - `string`类型在C#中是...

    CSDN网摘右链添加

    标题"CSDN网摘右链添加"涉及到的是在Windows操作系统中通过修改注册表来增加或删除CSDN网摘的快捷方式。CSDN(China Software Developer Network)是中国的一个知名IT技术社区,提供了丰富的编程资源、论坛讨论以及...

    Finn.no物业地图助理「Finn.no Property Map Assistant」-crx插件

    如果两个或两个以上的人使用扩展名,并希望合并他们保存/隐藏的属性,他们可以使用这种形式: https://jsfiddle.net/0khx2t89/16/ 冲突(财产被保存和隐藏)将显示为黄色感叹号(!)。 笔记和已知问题: - 这个...

    React 17 道面试题及答案.docx

    2. getDerivedStateFromProps:static getDerivedStateFromProps(nextProps, prevState),这是个静态方法,当我们接收到新的属性想去修改我们 state,可以使用 getDerivedStateFromProps。 3. render:render 函数是...

    download-reddit-saved-images:此脚本检查您保存的链接并搜索图像以自动将它们下载到文件夹中

    下载-reddit-保存的图像 此脚本会检查您保存的链接并搜索图像...决定下载方法的新方法。 更干净的代码。 1.1.0 修复了几个错误 1.0.2 重构 Bug修复 添加了对 YAML 的支持 0.2.3.0 修复了导致相册在同一张照片上保存

    Java 47 道面试题及答案.docx

    虚拟 DOM 的缺点是无法进行极致优化,可以在一些性能要求极高的应用中使用手动操作 DOM。 三、虚拟 DOM 的实现原理 虚拟 DOM 的实现原理是: 1. 虚拟 DOM 本质上是 JavaScript 对象,是对真实 DOM 的抽象。 2. ...

Global site tag (gtag.js) - Google Analytics