`
lxz891117
  • 浏览: 33303 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

Hibernate:unsaved-value

 
阅读更多
当你显式的使用session.save()或者session.update()操作一个对象的时候,实际上是用不到unsaved-value的。某些情况下(父子表关联保存),当你在程序中并没有显式的使用save或者update一个持久对象,那么Hibernate需要判断被操作的对象究竟是一个已经持久化过的持久对象,是一个尚未被持久化过的内存临时对象。例如:

Java代码
  1. Sessionsession=...;
  2. Transactiontx=...;
  3. Parentparent=(Parent);session.load(Parent.class,id);;
  4. Childchild=newChild();;
  5. child.setParent(parent);;
  6. child.setName("sun");;
  7. parent.addChild(child);;
  8. s.update(parent);;
  9. s.flush();;
  10. tx.commit();;
  11. 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)

例如下面的情况:

Java代码
  1. Sessionsession=...;
  2. Transactiontx=...;
  3. Parentparent=(Parent);session.load(Parent.class,id);;
  4. Childchild=(Child);session.load(Child.class,childId);;
  5. child.setParent(parent);;
  6. child.setName("sun");;
  7. parent.addChild(child);;
  8. s.update(parent);;
  9. s.flush();;
  10. tx.commit();;
  11. 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类的主键属性中的。

Java代码
  1. <classname="Child"table="child">
  2. <idcolumn="id"name="id"type="integer"unsaved-value="null">
  3. <generatorclass="identity"/>
  4. </id>
  5. ...
  6. </class>


如果主键属性不是对象型,而是基本类型,如int/long/double/...,那么你需要指定一个数值型的unsaved-value,例如:

Java代码
  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/..了。
分享到:
评论

相关推荐

    hibernate-mapping参数详解

    unsaved-value (可选 - 默认为 null) 此属性用于指定一个未保存状态的值。如果实体的某个属性被标记为此值,则表示该实体尚未被持久化。这对于检测实体的状态非常有用,尤其是在 session 中修改实体之前。 #### 5...

    Hibernate开发指南

    - **unsaved-value**: Hibernate中的一种特殊值,用于标识未保存的对象状态。 ##### 9. 事务管理 - **基于JDBC的事务管理**: - 使用Connection对象的commit()和rollback()方法控制事务。 - **基于JTA的事务管理**...

    Hibernate 开发学习指导书

    - **关于unsaved-value**: Hibernate的一个特性,用于标记尚未保存到数据库中的值。 - **Inverse和Cascade**: 用于控制关联关系的更新和级联操作。 - **延迟加载** (Lazy Loading): 一种优化技术,仅在真正需要时才...

    Hibernate入门 - 基础配置

    &lt;id name="id" unsaved-value="0"&gt; &lt;property name="name" not-null="true"/&gt; &lt;loader query-ref="person"/&gt; &lt;sql-insert&gt;INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )&lt;/sql-insert&gt; &lt;sql-update...

    Hibernate主键类型说明和配置手册.doc

    &lt;id name="id" unsaved-value="null"&gt; ``` 2. **sequence**: 此策略适用于支持序列的数据库,如Oracle。你需要指定一个序列名,如下所示: ```xml &lt;id name="id" unsaved-value="0"&gt; ...

    最经典的hibernate教程

    - `unsaved-value`: 未保存的值。 - `access`: 访问策略。 - **&lt;generator&gt; 元素**: 定义主键的生成策略。 - `class`: 生成器类名。 **3.3 &lt;property&gt; 元素** - 用于映射 Java 类中的属性到数据库表中的列。 -...

    hibernate映射文件的详解

    如果对象的标识属性值等于`unsaved-value`,Hibernate会认为该实例是新创建的,需要执行`save`操作;否则,执行`update`操作。 4. 主键生成器(Key Generator):用于决定如何生成对象的唯一标识(主键)。`...

    hibernate入门级教程,零基础哟

    - **特殊属性处理**:如`unsaved-value`用于标记未保存的对象状态。 - **Inverse和Cascade**:Inverse属性指定关联的哪一方负责维护关系;Cascade属性允许在操作实体时自动触发其他操作。 - **延迟加载**:一种优化...

    hibernate常见错误解决方案

    **TransientObjectException: object references an unsaved transient instance** **异常描述:** 此异常表示一个实体引用了另一个尚未保存的瞬态实体。 **解决方法:** - 在保存实体之前先保存所有关联的瞬态...

    hibernate配置元素例子.txt

    - **`unsaved-value`属性**:未保存状态的值,此处设置为`null`表示当实体处于未保存状态时,该字段的值为`null`。 - **`generator`子元素**:定义主键的生成策略,这里采用`uuid.hex`,意味着使用基于UUID的十六...

    Hibernate version 乐观锁 (xml方式)

    在这个配置中,`&lt;version&gt;`标签用于声明乐观锁的版本字段,`column`属性指定数据库对应的列名,`unsaved-value`属性表示未保存的初始值。 在实际的业务逻辑中,当我们试图更新一个用户时,Hibernate会在更新SQL语句...

    夏昕-Hibernate+开发指南.pdf

    - **数据访问**:探讨了PO(Plain Old Java Object)和VO(Value Object)的区别,以及unsaved-value、Inverse和Cascade、延迟加载等概念。 - **事务管理**:介绍了基于JDBC和JTA的事务处理方法。 - **锁机制**:讲解...

Global site tag (gtag.js) - Google Analytics