2012年3月20日星期二

the best xml dom4j saxreader tutorial

Tutorial: Introduction to XML and Java: XML, dom4j and XPath

利用Dom4J的SAXReader解析大文件 - - ITeye技术网站

利用Dom4J的SAXReader解析大文件 - - ITeye技术网站

今天用到了对内容量很大的XML文件的解析,顺便记录一下。 



      关于XML的解析技术网上有很多文章,不再详述。 主要的方式有JDK自带的JAXP(Java API For XML Parser)、JDom、Dom4j等。其中Dom4J是相当灵活的,很多开源框架都基于Dom4J来做XML解析。 

      底层的解析器主要有两种: DOM、SAX。 其中DOM作为树型结构将文本装载到内存中,适合文本内容比较小的;SAX则按照流的方式扫描,事件触发的方式供你处理,比如遇到某个结点的开始符,结束符,大文本不能一次性装载到内存中,就应该采用SAX方式。 



      DOM4J利用SAXReader类来读取文件,然后为SAXReader对象设置元素处理解析器ElementHandler,有doStart和doEnd两个方法,分别在遇到元素的开始符号和结束符号时候触发。只需在相应的方法内实现自己的业务逻辑即可。 



例子:  XML文件结构如下: 

view plaincopy to clipboardprint?<?xml version="1.0" encoding="GB2312"?>  
<TESTINFO version="1.0">  
    <UPDATEINFO>  
        <PARAM_TIMESTAMP>2010-12-22 09:54:09</PARAM_TIMESTAMP>  
        <CITYINFO_LIST>  
            <CITYINFO City="591" Name="XYZ" No="334" />  
            <CITYINFO City="591" Name="BJD" No="335" />  
            <CITYINFO City="591" Name="UUS" No="390" />  
        </CITYINFO_LIST>  
    </UPDATEINFO>  
</TESTINFO>  
<?xml version="1.0" encoding="GB2312"?> 
<TESTINFO version="1.0"> 
<UPDATEINFO> 
<PARAM_TIMESTAMP>2010-12-22 09:54:09</PARAM_TIMESTAMP> 
<CITYINFO_LIST> 
<CITYINFO City="591" Name="XYZ" No="334" /> 
<CITYINFO City="591" Name="BJD" No="335" /> 
<CITYINFO City="591" Name="UUS" No="390" /> 
</CITYINFO_LIST> 
</UPDATEINFO> 
</TESTINFO> 




其中CITYINFO可能是个很大的列表。 完整的程序代码如下: 



view plaincopy to clipboardprint?package com.atu.xmltest;  
  
import java.io.InputStream;  
  
import org.dom4j.DocumentException;  
import org.dom4j.Element;  
import org.dom4j.ElementHandler;  
import org.dom4j.ElementPath;  
import org.dom4j.io.SAXReader;  
  
public class MySaxHandler implements ElementHandler {  
      
    SAXReader reader;  
    public MySaxHandler() {  
        // test.xml文件跟类放在同一目录下   
        try {  
            InputStream is = MySaxHandler.class.getResourceAsStream("test.xml");   
            reader = new SAXReader();  
            reader.setDefaultHandler(this);  
            reader.read(is);  
        } catch (DocumentException e) {  
            e.printStackTrace();  
        }  
    }  
    @Override  
    public void onEnd(ElementPath ep) {  
        Element e = ep.getCurrent(); //获得当前节点   
        if(e.getName().equals("PARAM_TIMESTAMP"))  
            System.out.println("解析到时间:"+e.getText());  
        else if(e.getName().equals("CITYINFO")){  
            System.out.printf("解析到CITYINFO,属性值为:%s,%s,%s/n", e  
                    .attributeValue("City"), e.attributeValue("Name"), e  
                    .attributeValue("No"));  
        }  
        e.detach(); //记得从内存中移去   
    }  
  
    @Override  
    public void onStart(ElementPath ep) {  
    }  
      
    public static void main(String[] args){  
        new MySaxHandler();  
    }  
  
}  
package com.atu.xmltest; 

import java.io.InputStream; 

import org.dom4j.DocumentException; 
import org.dom4j.Element; 
import org.dom4j.ElementHandler; 
import org.dom4j.ElementPath; 
import org.dom4j.io.SAXReader; 

public class MySaxHandler implements ElementHandler { 

SAXReader reader; 
public MySaxHandler() { 
// test.xml文件跟类放在同一目录下 
try { 
InputStream is = MySaxHandler.class.getResourceAsStream("test.xml"); 
reader = new SAXReader(); 
reader.setDefaultHandler(this); 
reader.read(is); 
} catch (DocumentException e) { 
e.printStackTrace(); 


@Override 
public void onEnd(ElementPath ep) { 
Element e = ep.getCurrent(); //获得当前节点 
if(e.getName().equals("PARAM_TIMESTAMP")) 
System.out.println("解析到时间:"+e.getText()); 
else if(e.getName().equals("CITYINFO")){ 
System.out.printf("解析到CITYINFO,属性值为:%s,%s,%s/n", e 
.attributeValue("City"), e.attributeValue("Name"), e 
.attributeValue("No")); 

e.detach(); //记得从内存中移去 


@Override 
public void onStart(ElementPath ep) { 


public static void main(String[] args){ 
new MySaxHandler(); 








运行结果: 



解析到时间:2010-12-22 09:54:09 
解析到CITYINFO,属性值为:591,XYZ,334 
解析到CITYINFO,属性值为:592,BJD,335 
解析到CITYINFO,属性值为:593,UUS,390 

2012年3月19日星期一

hibernate一对多sort和order by_JAVA_百度空间

hibernate一对多sort和order by_JAVA_百度空间


  1. 從資料庫的觀點來看,Set、Map、Bag是無序的,而List是有序的,這邊所謂的無序或有序,是指將容器中物件儲存至資料庫時,是否依容器物件中的順序來儲存。   
  2.   
  3. 然而從資料庫取得資料之後,您也許會希望Set、Map等容器中的物件可以依一定的順序來排列,您可以從兩個層次來容器中的物件排序,一是在載入資料後於JVM中排序,另一是在資料庫中直接使用order by子句來排序。   
  4.   
  5. 以 Set 這篇文章中的範例來作說明,要在JVM中就資料進行排序,您可以在映射文件中使用sort屬性來定義容器的排序,這適用於Set與Map,例如:   
  6.   
  7. User.hbm.xml   
  8. <?xml version="1.0" encoding="utf-8"?>   
  9. <!DOCTYPE hibernate-mapping   
  10.      PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"   
  11.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">   
  12.   
  13. <hibernate-mapping>   
  14.   
  15.      <class name="onlyfun.caterpillar.User" table="user">   
  16.          ....   
  17.          <set name="emails" table="email" sort="natural">   
  18.              <key column="id"/>   
  19.              <element type="java.lang.String"   
  20.                       column="address"/>   
  21.          </set>   
  22.      </class>   
  23.   
  24. </hibernate-mapping>sort="natural"表示使用物件的comparaTo()方法來進行排序,容器中的物件上必須有實作java.lang.Comparable 介面,例如String就有實作java.lang.Comparable介面,結果會使用字典順序來排列容器中的物件。   
  25.   
  26. 您可以實現自己的排序方式,只要定義一個類別來實作java.util.Comparator介面,例如:   
  27.   
  28. CustomComparator.java   
  29. package onlyfun.caterpillar;   
  30.   
  31. import java.util.Comparator;   
  32.   
  33. public class CustomComparator implements Comparator {   
  34.     public int compare(Object o1, Object o2) {   
  35.         if (((String) o1).equals(o2))   
  36.             return 0;   
  37.         return ((Comparable) o1).compareTo(o2) * -1;   
  38.      }   
  39. }   
  40. 在自訂的Comparator中,如果兩個物件的順序相同會傳回0,而為了方便比較物件,要求傳入的物件必須實作Comparable介面(例如 String物件就有實作Comparable介面),範例中只是簡單的將原來compareTo()傳回的值乘以負一,如此就可以簡單的讓排列順序相反,接著可以在映射文件中指定自訂的Comparator類別:   
  41.   
  42. User.hbm.xml   
  43. <?xml version="1.0" encoding="utf-8"?>   
  44. <!DOCTYPE hibernate-mapping   
  45.      PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"   
  46.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">   
  47.   
  48. <hibernate-mapping>   
  49.   
  50.      <class name="onlyfun.caterpillar.User" table="user">   
  51.          ....   
  52.          <set name="emails" table="email"   
  53.               sort="onlyfun.caterpillar.CustomComparator">   
  54.              <key column="id"/>   
  55.              <element type="java.lang.String"   
  56.                       column="address"/>   
  57.          </set>   
  58.      </class>   
  59.   
  60. </hibernate-mapping>Bag與List並不適用於這種方式。   
  61.   
  62. 另一個排序的方式則是在資料庫中進行,直接使用order by子句來排序,這可以在映射文件中使用order-by屬性來指定,例如:   
  63.   
  64. User.hbm.xml   
  65. <?xml version="1.0" encoding="utf-8"?>   
  66. <!DOCTYPE hibernate-mapping   
  67.      PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"   
  68.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">   
  69.   
  70. <hibernate-mapping>   
  71.   
  72.      <class name="onlyfun.caterpillar.User" table="user">   
  73.          ....   
  74.          <set name="emails" table="email" order-by="address desc">   
  75.              <key column="id"/>   
  76.              <element type="java.lang.String"   
  77.                       column="address"/>   
  78.          </set>   
  79.      </class>   
  80.   
  81. </hibernate-mapping>觀察Hibernate所使用的SQL可以看到order by子句:   
  82.   
  83. Hibernate:   
  84. select emails0_.id as id0_, emails0_.address as address0_   
  85. from email emails0_ where emails0_.id=? order by emails0_.address desc     
  86. <PRE class=java name="code"></PRE>  

Re: 求助:房东检查我的垃圾要罚款(转寄)

发信人: Belsenming (Benlsen), 信区: Living
标 题: Re: 求助:房东检查我的垃圾要罚款
发信站: BBS 未名空间站 (Mon Mar 19 00:31:56 2012, 美东)

又一个可怜的孩子呀。

你刚来美国,还是留学生刚来?
不是傻B,就是你的房东变态,这样不合理,也是对你严重侵犯,房东知道你不可能去
找律师告的。

1。房东这样的租住合同是严重侵犯你的,没有这样的苛刻规定你要分开回收东西,全
是扯淡,先看看报纸找律师咨询一下。记住,即使你交了钱一定要收据,一样,我们住
公寓,那有什么回收东西分开,全是仍到一个大垃圾站。

2。 美国都是表演的天才之国度,房东总有失手的时候,在失手的同时也是你解脱之日
,我看到过一个例子,房东喜欢查看你,有your住的钥匙,哪天等你回家,她要是来过
你家,你先跑去问他,你有开门进去的吗?他mybe说我看看有没有虫子什么的,去过,
你事先把有利于你的谈话,录音下来,回去马上打911家里被盗了,3000块昨天下午取
的在银行,这里还有收据。等警察取证是播放你的录音。

3。再找房东就好商量,你这不安全,理由,你看只有你进过我门,还在我不在家的情况
下,你对我的侵犯,等等,我现在就搬家。拿出你事先准备的协议书签名搬家走人。

愚人之见。
--

※ 来源:・WWW 未名空间站 海外: mitbbs.com 中国: mitbbs.cn・[FROM: 72.181.]

2012年3月18日星期日

来BSO一下跟n个CAMRY DEALER战斗的结果(转寄)

发信人: SimFan (SimFan), 信区: Automobile
标 题: 来BSO一下跟n个CAMRY DEALER战斗的结果
发信站: BBS 未名空间站 (Sun Mar 18 05:20:26 2012, 美东)

这两天跑了5家TOYOTA DEALER,跑之前INTERNET QUOTE了20家,
打印了各种资料和QUOTES有两寸厚,一个大夹子带着信心十足
走入每个DEALERSHIP。另外带着电脑,充电器,水和食物。

进入DEALER店后,先拿出FOLDER有意无意给SALES看,不笑,
一直板着脸严肃状,先直接跟SALES约法三章:

1.我前后只有1个小时时间跟你讨论,没有结果我就走,期间
假装拿出DEALER LIST,打电话给下一家问一个小时后可不可以去。

2.不试驾,不看车,告诉他已经都看好,非常熟悉车的样子。

3.最后定下我满意的成交价前不给任何个人信息,
包括姓名(LAST NAME),家庭地址,公司地址等等,所有跟价格
无关的问题一概不回答,他们爱有啥表有啥表,我就是不填。不给
价格就走人,后来所有SALES都软了。

当然要留电话,以防万一我没谈成价格WALK OUT后,他们有更低价
打电话叫我。事后证明留电话留对了,找到最低OTD就是在我WALK
OUT 3分钟后,被电话叫回去的。

我上来直接给SALES我要的车的SPECIFICS,颜色,配置。我的OPTIONS
全部给CODE,比如PD, P2什么的。就给我BEAT我现在从别人拿到的最
低的OTD,MATCH都不行,一定要BEAT。一旦可以BEAT,我要求DEALER
打印详细OFFER,并且手机照相,因为他们都不会给那张纸的。如果
BEAT成功,OK,现在我就达到目的了,跟SALES说 PLEASE GIVE ME A
SECOND,我就出去打电话给另一下靠谱的DEALER,要求他们电话里面
BEAT我刚从这家拿到的最低价。然后再跑另一家。。。嘿嘿。

这里有个很重要的TIP。DEALER都是受过心里学训练的,我们没有受过
专业训练,容易袒露心理状态。所以一定要经常让SALES离开桌子,尤其
在你考虑他给的一个价格的时候,这个时候最容易暴露你的心里状态,
一定要跟SALES说,CAN YOU GIVE ME A MINUTE HERE, LEAVE ME ALONE,
AND I WILL THINK ABOUT IT。这样屋子或者CUBE只有你一个人对着DEALER
给的OFFER NUMBERS,随便你怎么算计,什么表情,SALES都不知道了,
这样一来,他们受过的训练一点都用不上。

还有一点,当SALES MANAGER出来的时候,他是来试探你的心理的,
一定要少说,而且尽量控制自己的表情,保持前后没有变化。

一个杀手锏:WALK OUT。你在北京秀水街,西单韩国店买过东西吗?如果
你买过,你一定知道WALK OUT的力量。其实这里买车一样。美国人很少有人
突然WALK OUT,所以这是对美国这些傻粗没见过世面的SALES最大最有效的
冲击。他们绝对会挽留你,这个时候你又占上风了。总之一切时候保持
气场压倒对方。WALK OUT没啥,大不了去别的家,大不了以后再回来,
大不了买别的车。我跟这5家DEALER斗的过程中,曾经有一次我都已经签
正式文件了,我选择WALK OUT,他们立刻软了,呵呵,又降价300。

另外谈判期间,我时不时拿出电话假装打电话给另外的DEALER问价格是不是
确定,无数次的挑战号称学过心理学行为学什么乱七八糟学的DEALER
的心理。包括几次他们的GENERAL SALES MANAGER都出来跟我谈,我还是
一直处在谈判上峰,保持极高的气场。

最后实践证明一切DEALER都是纸老虎,最后成交的那家是在我WALK OUT
后叫我回去,由FLEET SALES MANAGER直接跟我谈FLEET的卖价 :)))

好爽的砍价经历啊。有的DEALER的SALES MANAGER都扛不住了,问我谁
会出那么低的OTD,根本不可能做到,我给他看EMAIL,他想看是哪家
DEALER出的价,我直接回绝,说我不能告诉你。他让我DO HIM A FAVOR
告诉他是哪家,以后他们好更好的服务别的顾客。我说,NO, YOU CAN
ASK, BUT I DECLINE TO ANSWER。直接WALK OUT,哈哈哈。SALES MANAGER
说我TOUGH,我说YES YOU GOT IT BUT TOO LATE。

报价吧,最后,大家准备好了。2012 CAMRY SE ALMOST ALL PACKAGES
INCLUDED, MOON ROOF, ENTUNE, ALL LEATHER SEATS, EVERYTHING
INCLUDE $1000 FINANCE REBATE, DRIVE OUT $21,500。好爽!

估计我现在立刻卖掉也是赚钱的,呵呵。天下DEALER都是纸老虎,只要
大家做好功课,保持气场,拿下他们没问题!


--

※ 修改:・SimFan 于 Mar 18 12:53:33 2012 修改本文・[FROM: 173.74.]
※ 来源:・BBS 未名空间站 海外: mitbbs.com 中国: mitbbs.cn・[FROM: 173.74.]

院子:今年院子里蚊子很猖狂,反攻初见成效 - 由过客心径发表 - 文学城

院子:今年院子里蚊子很猖狂,反攻初见成效 - 由过客心径发表 - 文学城

2012年3月15日星期四

[原]Hibernate一对多(单向) - wintysのブログ - BlogJava

[原]Hibernate一对多(单向) - wintysのブログ - BlogJava


[标题]:Hibernate一对多(单向)
[时间]:2009-6-12
[摘要]:单向一对多关联只需要在"一方"进行配置即可,"多方"无需额外配置。
[关键字]:外键,inverse,Hibernate,Set,一对多,单向,ORM,mapping,关系数据库,映射
[环境]:MyEclipse7 , JDK6,Hibernate3.2,Tomcat6,MySQL 5.1.34-community
[作者]:Winty (wintys@gmail.com) http://www.blogjava.net/wintys

[正文]:
    Hibernate一对多关联,例如一个用户有多张银行卡(只考虑用户到银行卡的单向一对多关联)。由于是学习Hibernate原理,并没有使用工具自动生成代码等。
    单向一对多关联只需要在"一方"进行配置即可,"多方"无需额外配置。

a.Java程序中所要做的一对多:
public class User{
    ...
    private Set<Card> cards;
    ...
}

public class Card{
    ...
}


b.Hibernate中所要做的一对多:
User.hbm.xml:
...
<set name="cards" inverse="false" cascade="all">
    <key column="userId" />
    <one-to-many class="wintys.hibernate.onetomany.Card" />
</set>
...

c.数据库中的一对多:
而对应的数据库中,只要相应在Card对应的物理表中添加外键userId(不要设为NOT NULL)即可。


详细的MyEclipse WebProject如下:
1、实体类:
用户类User.java:
package wintys.hibernate.onetomany;

import java.util.Set;

public class User {
    private String id;
    private String name;
    private Set<Card> cards;
  
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setCards(Set<Card> cards) {
        this.cards = cards;
    }
    public Set<Card> getCards() {
        return cards;
    } 
}

银行卡类Card.java:
package wintys.hibernate.onetomany;

public class Card {
    private String id;
    private float balance;
  
    public Card(){
    }
    public Card(float balance){
        this.balance = balance;
    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public float getBalance() {
        return balance;
    }
    public void setBalance(float balance) {
        this.balance = balance;
    } 
}

2、数据库表:
数据库是MySQL 5.1.34-community。

用户表:
CREATE TABLE myuser(
    id               VARCHAR(50)  NOT NULL,
    name         VARCHAR(100),
    PRIMARY KEY(id)
);

银行卡表:
CREATE TABLE mycard(
    id               VARCHAR(50)  NOT NULL,
    balance      FLOAT(7,2),
    userId       VARCHAR(50),
    PRIMARY KEY(id)
);


3、映射文件:
用户类映射文件/src/wintys/hibernate/onetomany/User.hbm.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
    Mapping file autogenerated by MyEclipse Persistence Tools
-->

<hibernate-mapping>
    <class name="wintys.hibernate.onetomany.User" table="myuser" catalog="db">
        <id name="id" type="string">
            <column name="id" not-null="true"/>
            <generator class="uuid.hex" />
        </id>
        <property name="name" type="java.lang.String" column="name" />
      
        <set name="cards" inverse="false" cascade="all">
            <key column="userId" />
            <one-to-many class="wintys.hibernate.onetomany.Card" />
        </set>
    </class>
</hibernate-mapping>


银行卡映射文件/src/wintys/hibernate/onetomany/User.hbm.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
    Mapping file autogenerated by MyEclipse Persistence Tools
-->

<hibernate-mapping>
    <class name="wintys.hibernate.onetomany.Card" table="mycard" catalog="db">
        <id name="id" type="string">
            <column name="id" not-null="true"/>
            <generator class="uuid.hex" />
        </id>
        <property name="balance" />
    </class>
</hibernate-mapping>


Hibernate配置文件:/src/hibernate.cfg.xml:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<!-- Generated by MyEclipse Hibernate Tools.                   -->
<hibernate-configuration>

<session-factory>
    <property name="connection.username">root</property>
    <property name="connection.url">
        jdbc:mysql://localhost:3306/db?useUnicode=true&amp;characterEncoding=utf-8
    </property>
    <property name="dialect">
        org.hibernate.dialect.MySQLDialect
    </property>
    <property name="myeclipse.connection.profile">MySQLDriver</property>
    <property name="connection.password">root</property>
    <property name="connection.driver_class">
        com.mysql.jdbc.Driver
    </property>
    <property name="show_sql">true</property>
    <mapping resource="wintys/hibernate/onetomany/User.hbm.xml" />
    <mapping resource="wintys/hibernate/onetomany/Card.hbm.xml" />

</session-factory>

</hibernate-configuration>


4、使用测试:
/src/wintys/hibernate/onetomany/HibernateDAO.java:
package wintys.hibernate.onetomany;
import java.util.List;

public interface HibernateDAO {
    public void insert();
    public List<User> selectAll();
}



/src/wintys/hibernate/onetomany/HibernateDAOBean.java:
package wintys.hibernate.onetomany;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;

public class HibernateDAOBean implements HibernateDAO {

    public void insert() throws HibernateException {
        Transaction tc = null;
        try{
            Set<Card> cards = new HashSet<Card>();
            Card c1,c2,c3;
            c1 = new Card(7641.96f);
            c2 = new Card(654.8f);
            c3 = new Card(3650f);
          
            cards.add(c1);
            cards.add(c2);
            cards.add(c3);
          
            User user = new User();
            user.setName("Tom");
            user.setCards(cards);
          
            Session session = HibernateUtil.getSession();
            tc = session.beginTransaction();
                      
            /*
            配置文件中的cascade="true"时,所以无需手动保存c1,c2,c3
            session.save(c1);
            session.save(c2);
            session.save(c3);
            */
            session.save(user);
          
            tc.commit();
        }catch(HibernateException e){
            try{
                if(tc != null)
                    tc.rollback();
            }catch(Exception ex){
                System.err.println(ex.getMessage());
            }
            System.err.println(e.getMessage());
        }finally{
            HibernateUtil.closeSession();         
        }
    }

    @SuppressWarnings("unchecked")
    public List<User> selectAll() throws HibernateException {
        List<User> users = null;
        Transaction tc = null;
        try{
            Session session = HibernateUtil.getSession();
            tc = session.beginTransaction();
                      
            Query query = session.createQuery("from User");
            users = query.list();
          
            tc.commit();
        }catch(HibernateException e){
            try{
                if(tc != null){
                    tc.rollback();
                    users = null;
                }
            }catch(Exception ex){
                System.err.println(ex.getMessage());
            }
            System.err.println(e.getMessage());
        }finally{
            //HibernateUtil.closeSession();       
        }
      
        return users;
    }
}



/src/wintys/hibernate/onetomany/HibernateUtil.java:
package wintys.hibernate.onetomany;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

/**
 * Hibernate Session管理
 * @author Winty
 */
public class HibernateUtil {
    private static SessionFactory factory = null;
    private static ThreadLocal<Session> threadLocal;
      
    static {
        try{
            factory = new Configuration()
                    .configure()
                    .buildSessionFactory();
        }catch(HibernateException e){
            System.err.println(e.getMessage());
        }
      
        threadLocal = new ThreadLocal<Session>();
    }
  
    private HibernateUtil(){  
    }
  
    public static Session getSession()throws HibernateException{
        Session session = threadLocal.get();
        if(session == null){
            session = factory.openSession();
            threadLocal.set(session);
        }
      
        return session;
    }
  
    public static void closeSession()throws HibernateException{
        Session session = threadLocal.get();
        if(session != null){
            session.close();
        }
        threadLocal.set(null);
    }
}



/index.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%@ page import="wintys.hibernate.onetomany.*"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP 'index.jsp' starting page</title>
  </head>
 
  <body>
    <%
        List<User> users = null;
        HibernateDAO dao = new HibernateDAOBean();
        dao.insert();
        users = dao.selectAll();
      
        Iterator<User> it = users.iterator();
        while(it.hasNext()){
            User user = it.next();
            String id = user.getId();
            String name = user.getName();
            out.println("id:" + id + "<br />");
            out.println("name:" + name + "<br />");
            out.println("cards:<br />");
          
            Set<Card> cards = user.getCards();
            Iterator<Card> itc = cards.iterator();
            while(itc.hasNext()){
                Card card = itc.next();
                String cardId = card.getId();
                float balance = card.getBalance();
                out.println("&nbsp;&nbsp;&nbsp; cardId:" + cardId + "<br />");
                out.println("&nbsp;&nbsp;&nbsp; balance:" + balance + "<br />");
            }
            out.println("<hr/>");
        }
  
     %>

  </body>
</html>


5、运行结果:
控制台显示:
......
Hibernate: insert into db.myuser (name, id) values (?, ?)
Hibernate: insert into db.mycard (balance, id) values (?, ?)
Hibernate: insert into db.mycard (balance, id) values (?, ?)
Hibernate: insert into db.mycard (balance, id) values (?, ?)
Hibernate: update db.mycard set userId=? where id=?
Hibernate: update db.mycard set userId=? where id=?
Hibernate: update db.mycard set userId=? where id=?
......


index.jsp页面显示:
id:402881e421d4d0be0121d4d20e140005
name:Tom
cards:
    cardId:402881e421d4d0be0121d4d20e230008
    balance:654.8
    cardId:402881e421d4d0be0121d4d20e230006
    balance:7641.96
    cardId:402881e421d4d0be0121d4d20e230007
    balance:3650.0


6、注意的问题:
a、错误提示:Field 'userId' doesn't have a default value。
    一开始把"userId"设成NOT NULL,但是Hibernate先执行的是:
"insert into db.mycard (balance, id) values (?, ?)"
然后才执行"update db.mycard set userId=? where id=?",
而userId在insert时是没有写入值的,所以就会报错。把userId的NOT NULL去掉即可。
b、User.hbm.xml中要设置cascade="all",或其它有效值,不然,在保存User对象时,相关的Card对象不会被保存。
c、User.hbm.xml中set标签的inverse属性不能设置为"true",inverse的默认值是"false",所以不加 inverse也可以。看书上说:在一对多的关联关系实现中,最好设置inverse="true",将有助于性能的改善。所以一开始就用了 inverse="true",User和Card对象都分别正确写入数据库了,但是就是userId字段没有被自动写入。
myuser表:
+--------------------------------------------+------+
| id                                 | name |
+--------------------------------------------+------+
| 402881e421d4d0be0121d4d20e140005  | Tom  |
+--------------------------------------------+------+
mycard表:
+--------------------------------------------+---------+---------
| id                                | balance | userId
+--------------------------------------------+---------+---------
| 402881e421d4d0be0121d4d20e230006  | 7641.96 | NULL
| 402881e421d4d0be0121d4d20e230007  | 3650.00 | NULL
|
| 402881e421d4d0be0121d4d20e230008  |  654.80  | NULL
+--------------------------------------------+---------+---------
搞了半天,原来在本例应该把inverse设为false。inverse还是很有用的,只是用错了地方。

[参考资料]:
[1] Hibernate 一对多外键单向关联--熔 岩 : http://lavasoft.blog.51cto.com/62575/39317
[2] Hibernate应用(二)单向一对多及双向一对多的配置: http://suhaoyuan.spaces.live.com/Blog/cns!2659D3AC8253C554!217.entry
[3] Hibernate单向一对多应注意的问题 : http://blog.chinaunix.net/u2/88320/showart_1716296.html
[4] hibernate一对多例子-已更新(二) : http://www.blogjava.net/wujun/archive/2008/08/04/39700.html