隨筆 - 117  文章 - 72  trackbacks - 0

          聲明:原創(chuàng)作品(標(biāo)有[原]字樣)轉(zhuǎn)載時請注明出處,謝謝。

          常用鏈接

          常用設(shè)置
          常用軟件
          常用命令
           

          訂閱

          訂閱

          留言簿(7)

          隨筆分類(130)

          隨筆檔案(123)

          搜索

          •  

          積分與排名

          • 積分 - 155774
          • 排名 - 390

          最新評論

          [標(biāo)題]:Hibernate一對多(單向)
          [時間]:2009-6-12
          [摘要]:單向一對多關(guān)聯(lián)只需要在"一方"進(jìn)行配置即可,"多方"無需額外配置。
          [關(guān)鍵字]:外鍵,inverse,Hibernate,Set,一對多,單向,ORM,mapping,關(guān)系數(shù)據(jù)庫,映射
          [環(huán)境]:MyEclipse7 , JDK6,Hibernate3.2,Tomcat6,MySQL 5.1.34-community
          [作者]:Winty (wintys@gmail.com) http://www.aygfsteel.com/wintys

          [正文]:
              Hibernate一對多關(guān)聯(lián),例如一個用戶有多張銀行卡(只考慮用戶到銀行卡的單向一對多關(guān)聯(lián))。由于是學(xué)習(xí)Hibernate原理,并沒有使用工具自動生成代碼等。
              單向一對多關(guān)聯(lián)只需要在"一方"進(jìn)行配置即可,"多方"無需額外配置。

          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.數(shù)據(jù)庫中的一對多:
          而對應(yīng)的數(shù)據(jù)庫中,只要相應(yīng)在Card對應(yīng)的物理表中添加外鍵userId(不要設(shè)為NOT NULL)即可。


          詳細(xì)的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、數(shù)據(jù)庫表:
          數(shù)據(jù)庫是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、運(yùn)行結(jié)果:
          控制臺顯示:
          ......
          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"設(shè)成NOT NULL,但是Hibernate先執(zhí)行的是:
          "insert into db.mycard (balance, id) values (?, ?)"
          然后才執(zhí)行"update db.mycard set userId=? where id=?",
          而userId在insert時是沒有寫入值的,所以就會報錯。把userId的NOT NULL去掉即可。
          b、User.hbm.xml中要設(shè)置cascade="all",或其它有效值,不然,在保存User對象時,相關(guān)的Card對象不會被保存。
          c、User.hbm.xml中set標(biāo)簽的inverse屬性不能設(shè)置為"true",inverse的默認(rèn)值是"false",所以不加inverse也可以。看書上說:在一對多的關(guān)聯(lián)關(guān)系實現(xiàn)中,最好設(shè)置inverse="true",將有助于性能的改善。所以一開始就用了inverse="true",User和Card對象都分別正確寫入數(shù)據(jù)庫了,但是就是userId字段沒有被自動寫入。
          myuser表:
          +--------------------------------------------+------+
          | id                                 | name |
          +--------------------------------------------+------+
          | 402881e421d4d0be0121d4d20e140005  | Tom  |
          +--------------------------------------------+------+
          mycard表:
          +--------------------------------------------+---------+---------
          | id                                | balance | userId
          +--------------------------------------------+---------+---------
          | 402881e421d4d0be0121d4d20e230006  | 7641.96 | NULL
          | 402881e421d4d0be0121d4d20e230007  | 3650.00 | NULL
          |
          | 402881e421d4d0be0121d4d20e230008  |  654.80  | NULL
          +--------------------------------------------+---------+---------
          搞了半天,原來在本例應(yīng)該把inverse設(shè)為false。inverse還是很有用的,只是用錯了地方。

          [參考資料]:
          [1] Hibernate 一對多外鍵單向關(guān)聯(lián)--熔 巖 : http://lavasoft.blog.51cto.com/62575/39317
          [2] Hibernate應(yīng)用(二)單向一對多及雙向一對多的配置: http://suhaoyuan.spaces.live.com/Blog/cns!2659D3AC8253C554!217.entry
          [3] Hibernate單向一對多應(yīng)注意的問題 : http://blog.chinaunix.net/u2/88320/showart_1716296.html
          [4] hibernate一對多例子-已更新(二) : http://www.aygfsteel.com/wujun/archive/2008/08/04/39700.html
          原創(chuàng)作品,轉(zhuǎn)載請注明出處。
          作者:Winty (wintys@gmail.com)
          博客:http://www.aygfsteel.com/wintys

          posted on 2009-06-13 00:12 天堂露珠 閱讀(12840) 評論(4)  編輯  收藏 所屬分類: Hibernate

          FeedBack:
          # re: [原]Hibernate一對多(單向) 2009-06-13 09:19 metadmin
          級聯(lián)查詢,好復(fù)雜,而且容易出錯。我和周邊搞金融開發(fā)的朋友都不大用。


          ---------------------------------
          解開權(quán)限與業(yè)務(wù)耦合,提高開發(fā)效率
          細(xì)粒度權(quán)限管理軟件 試用版下載
          http://www.metadmin.com

            回復(fù)  更多評論
            
          # re: [原]Hibernate一對多(單向) 2011-07-27 14:31 heoolo
          謝謝分享,很詳細(xì)  回復(fù)  更多評論
            
          # re: [原]Hibernate一對多(單向) 2014-04-29 11:54 11
          很帥氣~  回復(fù)  更多評論
            
          # re: [原]Hibernate一對多(單向) 2016-03-04 15:04 87
          太感謝了 非常仔細(xì)
            回復(fù)  更多評論
            
          主站蜘蛛池模板: 舞阳县| 河东区| 仪征市| 杭锦旗| 札达县| 新竹县| 历史| 桐柏县| 息烽县| 东乡县| 衢州市| 青浦区| 顺义区| 新安县| 虎林市| 天气| 儋州市| 曲周县| 盐亭县| 大城县| 桑植县| 呼伦贝尔市| 芦溪县| 鄂伦春自治旗| 六盘水市| 通山县| 屏山县| 岫岩| 滦平县| 泰顺县| 永泰县| 沅江市| 桂平市| 涪陵区| 新田县| 乳山市| 天长市| 五原县| 比如县| 泗水县| 山西省|