unsavedvalue是表示一个对象是新的还是旧的如果unsavedvalue=none那么就是新的就会被insert到数据库中如果unsavedvalue=any就是说明对象是从数据库中load的被update到数据库中
我的问题是unsavedvalue是由我们来强制说明这个对象是新的还是旧的那如果我把一个对象的unsavedvalue设置为any那我要new 一个对象把他save到数据库中怎么做呢?我感觉这不是矛盾了吗?主要是我们在写配置文件的时候怎么能说一个对象就一定是new的还是load的?
当你显式的使用sessionsave()或者sessionupdate()操作一个对象的时候实际上是用不到unsavedvalue的某些情况下(父子表关联保存)当你在程序中并没有显式的使用save或者update一个持久对象那么Hibernate需要判断被操作的对象究竟是一个已经持久化过的持久对象是一个尚未被持久化过的内存临时对象例如
代码:
Session session = ;
Transaction tx = ;
Parent parent = (Parent) sessionload(Parentclass id);
Child child = new Child();
childsetParent(parent);
childsetName(sun);
parentaddChild(child);
supdate(parent);
sflush();
mit();
sclose();
在上例中程序并没有显式的sessionsave(child); 那么Hibernate需要知道child究竟是一个临时对象还是已经在数据库中有的持久对象如果child是一个新创建的临时对象(本例中就是这种情况)那么Hibernate应该自动产生sessionsave(child)这样的操作如果child是已经在数据库中有的持久对象那么Hibernate应该自动产生sessionupdate(child)这样的操作
因此我们需要暗示一下Hibernate究竟child对象应该对它自动save还是update在上例中显然我们应该暗示Hibernate对child自动save而不是自动update那么Hibernate如何判断究竟对child是save还是update呢?它会取一下child的主键属性 childgetId() 这里假设id是 javalangInteger类型的如果取到的Id值和hbm映射文件中指定的unsavevalue相等那么Hibernate认为child是新的内存临时对象发送save如果不相等那么Hibernate认为child是已经持久过的对象发送update
unsavedvalue=null (默认情况适用于大多数对象类型主键 Integer/Long/String/)
当Hibernate取一下child的Id取出来的是null(在上例中肯定取出来的是null)和unsavedvalue设定值相等发送save(child)
当Hibernate取一下child的id取出来的不是null那么和unsavedvalue设定值不相等发送update(child)
例如下面的情况
代码:
Session session = ;
Transaction tx = ;
Parent parent = (Parent) sessionload(Parentclass id);
Child child = (Child) sessionload(Childclass childId);
childsetParent(parent);
childsetName(sun);
parentaddChild(child);
supdate(parent);
sflush();
mit();
sclose();
child已经在数据库中有了是一个持久化的对象不是新创建的因此我们希望Hibernate发送update(child)在该例中Hibernate取一下childgetId()和unsavevalue指定的null比对一下发现不相等那么发送update(child)
BTW: parent对象不需要操心因为程序显式的对parent有load操作和update的操作不需要Hibernate自己来判断究竟是save还是update了我们要注意的只是child对象的操作另外unsavedvalue是定义在Child类的主键属性中的
代码:
<class name=Child table=child>
<id column=id name=id type=integer unsavedvalue=null>
<generator class=identity/>
</id>
</class>
如果主键属性不是对象型而是基本类型如int/long/double/那么你需要指定一个数值型的unsavedvalue例如
代码:
unsavednull=
在此提醒大家很多人以为对主键属性定义为int/long比定义为Integer/Long运行效率来得高认为基本类型不需要进行对象的封装和解构操作因此喜欢把主键定义为int/long的但实际上Hibernate内部总是把主键转换为对象型进行操作的就算你定义为int/long型的Hibernate内部也要进行一次对象构造操作返回给你的时候还要进行解构操作效率可能反而低也说不定因此大家一定要扭转一个观点在Hibernate中主键属性定义为基本类型并不能够比定义为对象型效率来的高而且也多了很多麻烦因此建议大家使用对象型的Integer/Long定义主键
unsavedvalue=none和
unsavedvalue=any
主主要用在主键属性不是通过Hibernate生成而是程序自己setId()的时候
在这里多说一句强烈建议使用Hibernate的id generator或者你可以自己扩展Hibernate的id generator特别注意不要使用有实际含义的字段当做主键来用!例如用户类User很多人喜欢用用户登陆名称做为主键这是一个很不好的习惯当用户类和其他实体类有关联关系的时候万一你需要修改用户登陆名称一改就需要改好几张表中的数据偶合性太高而如果你使用无业务意义的id generator那么修改用户名称就只修改user表就行了
由这个问题引申出来如果你严格按照这个原则来设计数据库那么你基本上是用不到手工来setId()的你用Hibernate的id generator就OK了因此你也不需要了解当
unsavedvalue=none和
unsavedvalue=any
究竟有什么含义了如果你非要用assigned不可那么继续解释一下
unsavedvalue=none 的时候由于不论主键属性为任何值都不可能为none因此Hibernate总是对child对象发送update(child)
unsavedvalue=any 的时候由于不论主键属性为任何值都肯定为any因此Hibernate总是对child对象发送save(child)
大多数情况下你可以避免使用assigned只有当你使用复合主键的时候不得不手工setId()这时候需要你自己考虑究竟怎么设置unsavedvalue了根据你自己的需要来定
BTW: Gavin King强烈不建议使用compositeid强烈建议使用UserType
因此如果你在系统设计的时候遵循如下原则
使用Hibernate的id generator来生成无业务意义的主键不使用有业务含义的字段做主键不使用assigned
使用对象类型(String/Integer/Long/)来做主键而不使用基础类型(int/long/)做主键
不使用compositeid来处理复合主键的情况而使用UserType来处理该种情况
那么你永远用的是unsavedvalue=null 不可能用到any/none/了