`

Hibernate一对多(单向)

阅读更多

[标题]: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

原创作品,转载请注明出处。
作者:Winty (wintys@gmail.com)
博客:http://www.blogjava.net/wintys


  • 大小: 40.9 KB
  • 大小: 121.6 KB
分享到:
评论

相关推荐

    Hibernate一对多单向关联映射

    **标题:“Hibernate一对多单向关联映射”** 在Java持久化框架Hibernate中,一对多关系是常见的数据关联模式,它表示一个实体可以与多个其他实体相关联。在这个主题中,我们将深入探讨如何在Hibernate中实现一对多...

    Hibernate一对多单向关联(annotation/xml)

    在本教程中,我们将探讨如何使用注解和XML配置实现Hibernate的一对多单向关联。 首先,让我们理解一对多关联的概念。在数据库中,一对多关联意味着在一个表(父表)中的一个记录可以对应另一个表(子表)中的多个...

    hibernate多对一单向关联关系实现源码

    以上就是关于Hibernate中实现多对一单向关联关系的基本知识,包括如何在实体类中定义关联、如何进行数据库操作以及如何查询关联对象。这个源代码示例应该提供了更具体的实现细节,你可以通过查看和运行它来深入理解...

    Hibernate学习:单向多对一关联 工程

    本项目“Hibernate学习:单向多对一关联 工程”专注于讲解Hibernate中的单向多对一关联映射,这是数据库设计中常见的关系类型,尤其在处理具有层次结构的数据时。 单向多对一关联指的是在一个实体类中有一个引用,...

    Hibernate 系列教程 单向一对多

    本教程聚焦于Hibernate中的单向一对多关联映射,这是一个常见的实体关系模型,广泛应用于各种业务场景。 在数据库设计中,一对多关系意味着一个父表记录可以与多个子表记录相关联。例如,一个学生可以有多个课程,...

    Hibernate基于连接表的一对多单向关联

    标题 "Hibernate基于连接表的一对多单向关联" 涉及的是数据库对象关系映射(ORM)框架Hibernate中的一个重要概念。在Java开发中,Hibernate是广泛使用的工具,它允许开发者将Java类与数据库表进行映射,简化了数据...

    Hibernate基于外键的一对多单向关联

    “Hibernate基于外键的一对多单向关联”这个标题指的是在Java持久化框架Hibernate中,如何通过外键实现一个实体类(如订单)与另一个实体类(如商品)之间的一对多关系,并且这种关联是单向的,即从订单端可以访问到...

    hibernate多对多单向关联

    总结来说,Hibernate中的多对多单向关联是一种高效的数据映射方式,它允许我们在不增加复杂性的情况下处理两个实体之间的复杂关系。通过学习和实践,开发者能够更好地掌握这种关联类型,从而在实际项目中灵活运用。

    Hibernate 一对多外键单向关联

    在Java持久化框架Hibernate中,一对多外键单向关联是一种常见的关系映射方式,它描述了一对多的关系,其中一个实体(例如Person)可以与多个其他实体(例如Address)相关联,而关联的方向只从多方(Address)指向...

    hibernate单向一对多关联映射(注解版)

    在Java的持久化框架Hibernate中,单向一对多关联映射是常见的数据关系处理方式,尤其是在处理数据库中的实体类和表之间的关系时。本主题主要关注如何使用注解来实现这种映射。Hibernate通过注解使得对象关系映射...

    hibernate单向多对多映射(注解版)

    3. `@JoinColumn`: 定义一对一或一对多关系中的外键字段,这里用在`@JoinTable`中,表示多对多关系的连接表中外键的属性。 在上述代码中,`Student`实体有一个`courses`集合,它包含了与之关联的所有`Course`实体。...

    Hibernate单向一对多关联映射(XML版)

    在本主题"Hibernate单向一对多关联映射(XML版)"中,我们将深入探讨如何使用XML配置来实现数据库中一个实体类对应多个实体类的关联关系。 在Hibernate中,一对多关联是一种常见的关系映射类型,它反映了数据库中的...

    hibernate 单向多对多关联映射练习

    本练习主要关注的是Hibernate中的单向多对多关联映射,这是一种常见的关系数据库设计模式,用于表示两个实体间复杂的关系。 在多对多关联中,两个实体类可以相互拥有多个实例,但只在一个方向上建立关联。例如,...

    Hibernate关于注解的一对多,多对多,一对一

    本篇文章将深入探讨Hibernate中注解的一对多、多对多和一对一关系映射。 ### 一对多关系 在现实生活中,例如一个班级有一个班主任,而班主任可以管理多个学生,这就是典型的“一对多”关系。在Hibernate中,我们...

Global site tag (gtag.js) - Google Analytics