WEB开发网      濠电姷鏁告繛鈧繛浣冲洤纾瑰┑鐘宠壘閻ょ偓銇勯幇鍫曟闁稿鍠愰妵鍕冀閵娧佲偓鎺楁⒒閸曨偄顏柡宀嬬畱铻e〒姘煎灡绗戦梻浣筋嚙濮橈箓顢氳濠€浣糕攽閻樿宸ュΔ鐘叉啞缁傚秹宕滆绾惧ジ寮堕崼娑樺缂佹宀搁弻鐔风暋閻楀牆娈楅梺璇″枓閺呯姴鐣疯ぐ鎺濇晝闁靛牆妫欓蹇旂節閻㈤潧浠﹂柛銊ョ埣楠炴劙骞橀鑲╋紱闂佽宕樼粔顔裤亹閹烘挸浜归梺缁樺灦閿曗晛螞閸曨垱鈷戦柟鑲╁仜婵″ジ鎮楀☉鎺撴珖缂侇喖顑呴鍏煎緞濡粯娅囬梻浣瑰缁诲倿寮绘繝鍥ㄦ櫇闁稿本绋撻崢鐢告煟鎼淬垻鈯曢柨姘舵煟韫囥儳绋荤紒缁樼箖缁绘繈宕橀妸褌绱濋梻浣筋嚃閸ㄤ即宕弶鎴犳殾闁绘梻鈷堥弫鍌炴煕閳锯偓閺呮瑧妲愬Ο琛℃斀闁绘劕妯婇崵鐔封攽椤旇棄鍔ら摶鐐烘煕閺囥劌澧柛娆忕箻閺屽秹宕崟顒€娅g紓浣插亾濠㈣泛顑囩粻楣冩煙鐎涙ḿ绠橀柨娑樼У椤ㄣ儵鎮欓鍕紙闂佽鍠栫紞濠傜暦閹偊妲诲┑鈩冨絻椤兘寮诲☉銏犖╅柕澶堝労閸斿绱撴担绋库偓鍝ョ矓瑜版帒鏋侀柟鍓х帛閺呮悂鏌ㄩ悤鍌涘 ---闂傚倸鍊烽悞锔锯偓绗涘厾娲煛閸涱厾顔嗛梺璺ㄥ櫐閹凤拷
开发学院WEB开发Jsp Java 中关于 unsaved-value 的问题 阅读

Java 中关于 unsaved-value 的问题

 2008-01-05 09:57:48 来源:WEB开发网 闂傚倸鍊风欢姘缚瑜嶈灋闁圭虎鍠栫粻顖炴煥閻曞倹瀚�闂傚倸鍊风粈渚€骞夐敓鐘插瀭闁汇垹鐏氬畷鏌ユ煙閹殿喖顣奸柛搴$У閵囧嫰骞掗幋婵冨亾閻㈢ǹ纾婚柟鐐灱濡插牊绻涢崱妤冃℃繛宀婁簽缁辨捇宕掑鎵佹瀸闂佺懓鍤栭幏锟�濠电姷鏁告慨顓㈠箯閸愵喖宸濇い鎾寸箘閹规洟姊绘笟鈧ḿ褍煤閵堝悿娲Ω閳轰胶鍔﹀銈嗗笂閼冲爼鍩婇弴銏$厪闁搞儮鏅涙禒褏绱掓潏鈺佷槐闁轰焦鎹囬弫鎾绘晸閿燂拷闂傚倸鍊风欢姘缚瑜嶈灋闁圭虎鍠栫粻顖炴煥閻曞倹瀚�  闂傚倸鍊烽懗鑸电仚缂備胶绮〃鍛村煝瀹ュ鍗抽柕蹇曞У閻庮剟姊虹紒妯哄妞ゆ劗鍘ч埥澶娢熼柨瀣偓濠氭⒑瑜版帒浜伴柛鎾寸☉閳绘柨顫濋懜纰樻嫼闂佸憡绋戦オ鏉戔枔閺冣偓缁绘稓浠﹂崒姘瀳闂佸磭绮幑鍥嵁鐎n亖鏀介柟閭﹀墯椤斿倹淇婇悙顏勨偓鏍ь潖婵犳艾鍌ㄧ憸蹇涘箟閹绢喗鏅搁柨鐕傛嫹
核心提示:unsaved-value是表示一个对象是新的还是旧的,假如unsaved-value=none那么就是新的,Java 中关于 unsaved-value 的问题,就会被insert到数据库中,假如unsaved-value=any就是说明对象是从数据库中load的,而使用UserType来处理该种情况, 那么你永远用

  unsaved-value是表示一个对象是新的还是旧的,假如unsaved-value=none 那么就是新的,就会被insert到数据库中,假如unsaved-value=any 就是说明对象是从数据库中load的,被update到数据库中。
  
  我的问题是:unsaved-value是由我们来强制说明这个对象是新的还是旧的,那假如我把一个对象的unsaved-value设置为any,那我要new 一个对象,把他save到数据库中,怎么做呢?我感觉这不是矛盾了吗?主要是我们在写配置文件的时候怎么能说一个对象就一定是new的还是load的?
  
  当你显式的使用session.save()或者session.update()操作一个对象的时候,实际上是用不到unsaved-value的。某些情况下(父子表关联保存),当你在程序中并没有显式的使用save或者update一个持久对象,那么Hibernate需要判定被操作的对象究竟是一个已经持久化过的持久对象,是一个尚未被持久化过的内存临时对象。例如:
  
  代码:
  Session session = ...;
  Transaction tx = ...;
  
  Parent parent = (Parent) session.load(Parent.class, id);
  
  Child child = new Child();
  child.setParent(parent);
  child.setName("sun");
  
  parent.addChild(child);
  s.update(parent);
  
  s.flush();
  tx.commit();
  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)
  
  例如下面的情况:
  
  代码:
  Session session = ...;
  Transaction tx = ...;
  
  Parent parent = (Parent) session.load(Parent.class, id);
  Child child = (Child) session.load(Child.class, childId);
  
  child.setParent(parent);
  child.setName("sun");
  
  parent.addChild(child);
  s.update(parent);
  
  s.flush();
  tx.commit();
  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类的主键属性中的。
  
  代码:
  <class name="Child" table="child">
  <id column="id" name="id" type="integer" unsaved-value="null">
   <generator class="identity"/>
  </id>
  ...
  </class>
  
  假如主键属性不是对象型,而是基本类型,如int/long/double/...,那么你需要指定一个数值型的unsaved-value,例如:
  
  代码:
  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/..了。

Tags:Java 关于 unsaved

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接