Hibernate 实体关联关系映射

Hibernate 实体关联关系映射
 

 

Hibernate的映射关系很多,也比较复杂,也很容易忘记。这个基本上占据了Hibernate学习的七成时间。熟悉这些映射模型,需要大量的实践才能掌握。下面是我对Hibernate关联关系映射的一个总结,放到blog上一是自己查看方便,二来也可以和更多Hibernate开发人员交流分享。希望各位多多留言哦:)。
        本文主要参考夏昕翻译的“Hibernate参考文档 V3.12”,也在附件中给出了。

 
本系列实例的开发环境:
 
Windows XP Professional 简体中文版
MySQL 5.0.45
Hibernate 3.12
Java SDK 1.5.06
IntelliJ IDEA 5.12
 
系列实例中所用的Hibernate配置文件如下:
 
<?xml version='1.0' encoding='gb2312'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        " http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!--指定连接数据库驱动-->
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <!--指定连接数据库的url,hibernate连接的数据库名-->
        <property name="connection.url">jdbc:mysql://localhost:3306/hbstudy</property>
        <!--指定连接数据库的用户名-->
        <property name="connection.username">root</property>
        <!--指定连接数据库的用户密码-->
        <property name="connection.password">leizhimin</property>
        <!--指定连接池的大小-->
        <property name="connection.pool_size">5</property>
        <!--指定数据库的方言-->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <!--根据需要自动创建数据库,测试环境用-->
        <property name="hbm2ddl.auto">create</property>
        <!--在控制台显示执行的SQL语句-->
        <property name="show_sql">true</property>
        <!-- Enable Hibernate's automatic session context management -->
        <property name="current_session_context_class">thread</property>
        <!--映射文件列表-->
        <!--单向关联-->
        <mapping resource="com/lavasoft/dx/_n_1_fk/Addressn1fk.hbm.xml"/>
        <mapping resource="com/lavasoft/dx/_n_1_fk/Personn1fk.hbm.xml"/>
        <mapping resource="com/lavasoft/dx/_n_1_tab/Addressn1tab.hbm.xml"/>
        <mapping resource="com/lavasoft/dx/_n_1_tab/Personn1tab.hbm.xml"/>
        <mapping resource="com/lavasoft/dx/_1_1_fk/Address11fk.hbm.xml"/>
        <mapping resource="com/lavasoft/dx/_1_1_fk/Person11fk.hbm.xml"/>
        <mapping resource="com/lavasoft/dx/_1_1_tab/Address11tab.hbm.xml"/>
        <mapping resource="com/lavasoft/dx/_1_1_tab/Person11tab.hbm.xml"/>
        <mapping resource="com/lavasoft/dx/_1_1_pk/Address11pk.hbm.xml"/>
        <mapping resource="com/lavasoft/dx/_1_1_pk/Person11pk.hbm.xml"/>
        <mapping resource="com/lavasoft/dx/_1_n_fk/Address1nfk.hbm.xml"/>
        <mapping resource="com/lavasoft/dx/_1_n_fk/Person1nfk.hbm.xml"/>
        <mapping resource="com/lavasoft/dx/_1_n_tab/Address1ntab.hbm.xml"/>
        <mapping resource="com/lavasoft/dx/_1_n_tab/Person1ntab.hbm.xml"/>
        <mapping resource="com/lavasoft/dx/_n_n/Addressnn.hbm.xml"/>
        <mapping resource="com/lavasoft/dx/_n_n/Personnn.hbm.xml"/>
        <!--双向关联-->
        <mapping resource="com/lavasoft/sx/_1_n_fk/Address1nfk_sx.hbm.xml"/>
        <mapping resource="com/lavasoft/sx/_1_n_fk/Person1nfk_sx.hbm.xml"/>
        <mapping resource="com/lavasoft/sx/_1_n_tab/Address1ntab_sx.hbm.xml"/>
        <mapping resource="com/lavasoft/sx/_1_n_tab/Person1ntab_sx.hbm.xml"/>
        <mapping resource="com/lavasoft/sx/_n_n/Addressnn_sx.hbm.xml"/>
        <mapping resource="com/lavasoft/sx/_n_n/Personnn_sx.hbm.xml"/>
        <mapping resource="com/lavasoft/sx/_1_1_fk/Address11fk_sx.hbm.xml"/>
        <mapping resource="com/lavasoft/sx/_1_1_fk/Person11fk_sx.hbm.xml"/>
        <mapping resource="com/lavasoft/sx/_1_1_pk/Address11pk_sx.hbm.xml"/>
        <mapping resource="com/lavasoft/sx/_1_1_pk/Person11pk_sx.hbm.xml"/>
        <mapping resource="com/lavasoft/sx/_1_1_tab/Address11tab_sx.hbm.xml"/>
        <mapping resource="com/lavasoft/sx/_1_1_tab/Person11tab_sx.hbm.xml"/>
    </session-factory>
</hibernate-configuration>
 
系列实例中所用到Session工厂是:
public class HibernateUtil {
    private static final SessionFactory sessionFactory;
    static {
        try {
            // Create the SessionFactory from hibernate.cfg.xml
            sessionFactory = new Configuration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            // Make sure you log the exception, as it might be swallowed
            System.err.println("初始化SessionFactory失败!" + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }
    public static final ThreadLocal session = new ThreadLocal();
    public static Session getCurrentSession() throws HibernateException {
        Session s = (Session) session.get();
        //当原Session为空或已关闭时,打开一个新的Session
        if (s == null || !s.isOpen()) {
            s = sessionFactory.openSession();
            session.set(s);
        }
        return s;
    }
    public static void closeSession() throws HibernateException {
        Session s = (Session) session.get();
        session.set(null);
        if (s != null) {
            s.close();
        }
    }
}
 
 

 

------------------------------------------------------------------------------------------------------

http://lavasoft.blog.51cto.com/62575/39398


 

 实体关联关系映射的种类:

单向关联
 一对一外键单向关联


  一对一主键单向关联
 一对一连接表单向关联
  一对多外键单向关联
 一对多连接表单向关联
 多对一外键单向关联
 多对一连接表单向关联
 多对多单向关联
双向关联
 一对一外键双向关联
一对一主键双向关联
 一对一连接表双向关联
 一对多外键双向关联
 一对多连接表双向关联
  多对多双向关联

 ------------------------------------------------------------------------------------------------------

 

 

 
自我学习笔记:
多对一关联映射(many to one):
我们以用户和组为例来讲述,因为一个用户只能属于一个组,而一个组可以有多个用户,故用户是多,组是一。但是用户和组分别属于不同的实体,用户要找到组,就需要每个用户持有组的一个引用。这样才能构成他们之间的关系。
关联映射的本质:
* 将关联关系映射到数据库,所谓的关联关系是对象模型在内存中的一个或多个引用
<many-to-one>会在多的一端加入一个外键,指向一的一端,这个外键是由<many-to-one>
中的column属性定义的,如果忽略了这个属性那么默认的外键与实体的属性一致

 
<many-to-one>标签的定义示例:
* <many-to-one name="group" column="groupid"/>
 
第一步:建立用户和组的实体类:如下
User实体:
public class User {
 
private int id;
 
private String name;
 
private Group group;//用户里持有组的引用

 
public int getId() {
return id;
}

 
public void setId(int id) {
this.id = id;
}

 
public String getName() {
return name;
}

 
public void setName(String name) {
this.name = name;
}

 
public Group getGroup() {
return group;
}

 
public void setGroup(Group group) {
this.group = group;
}
 
}

 
Group 实体:
public class Group {
 
private int id;
 
private String name;

 
public int getId() {
return id;
}

 
public void setId(int id) {
this.id = id;
}

 
public String getName() {
return name;
}

 
public void setName(String name) {
this.name = name;
}
}

 
第二步建立映射文件:
首先建立Group实体的映射文件,如下:
<hibernate-mapping>
<class name="com.bjsxt.hibernate.Group" table="t_group">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
</class>
</hibernate-mapping>

 
接着建立User实体的映射文件,如下:
<hibernate-mapping>
<class name="com.bjsxt.hibernate.User" table="t_user">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<!-- 
<many-to-one name="group" column="groupid" cascade="all"/>//设置级联属性,设置为all表示对删除,保存和修改都起作用
-->
<many-to-one name="group" column="groupid"/>
</class>
</hibernate-mapping>
第三部建立hibernate.cfg.xml文件:
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.url">jdbc:mysql://localhost/hibernate_many2one</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">bjsxt</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.show_sql">true</property>
 
<mapping resource="com/bjsxt/hibernate/User.hbm.xml"/>
<mapping resource="com/bjsxt/hibernate/Group.hbm.xml"/>
</session-factory>
</hibernate-configuration>

 
第四部写测试代码,以存储为例:
public class Many2OneTest extends TestCase {

 
public void testSave1() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
 
Group group = new Group();
group.setName("尚学堂");
 
User user1 = new User();
user1.setName("菜10");
user1.setGroup(group);
 
User user2 = new User();
user2.setName("容祖儿");
user2.setGroup(group);
 
//不能成功保存,抛出TransientObjectException异常
//因为Group为Tran sient状态,oid没有分配值
//persistent状态的对象是不能引用transient状态的对象的
session.save(user1);
session.save(user2);
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
 
public void testSave2() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
 
Group group = new Group();
group.setName("尚学堂");
 
session.save(group);
 
User user1 = new User();
user1.setName("菜10");
user1.setGroup(group);
 
User user2 = new User();
user2.setName("容祖儿");
user2.setGroup(group);
 
//可以正确存储
session.save(user1);
session.save(user2);
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
 
public void testSave3() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
 
Group group = new Group();
group.setName("尚学堂");
 
User user1 = new User();
user1.setName("菜10");
user1.setGroup(group);
 
User user2 = new User();
user2.setName("容祖儿");
user2.setGroup(group);
 
//不会抛出异常,因为采用了cascade属性,所以它会先保存Group
//采用cascade属性是解决TransientObjectException异常的一种手段
//cascade属性只对删除,保存和修改时起作用
session.save(user1);
session.save(user2);
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
 
public void testLoad1() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
User user = (User)session.load(User.class, 3);
System.out.println("user.name=" + user.getName());
System.out.println("user.group.name=" + user.getGroup().getName());
 
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
 
}

 

 

 

 

 
一对一关联关系映射(one to one):

一对一主键关联映射:让两个实体对象的id保持相同,这样可以避免多余的字段被创建。
两个对象之间的关系是一对一的关系,如用户和身份证的ID(Person 和 IdCard)
实现一对一关联关系映射有两种策略:

 
第一种是:主键关联。即让俩个对象具有相同的主键值,以表明他们之间的一对一的对应关系。这样数据库表不会有额外的字段来维护他们之间的关系,仅通过表的主               键来关联。
第二种是:唯一外键来关联。外键关联,本来是用于多对一的配置,但是加上唯一的限制之后,也可以用于表示一对一的关联关系。

 
下面我们以人和身份证俩个实体为例,来练习一对一的关联关系映射,我们采用主键关联:
第一步,分别建立人和身份证的实体类:如下
IdCaid的实体关系类为:
public class IdCard {
 
private int id;
 
private String cardNo;
 
public int getId() {
return id;
}

 
public void setId(int id) {
this.id = id;
}

 
public String getCardNo() {
return cardNo;
}

 
public void setCardNo(String cardNo) {
this.cardNo = cardNo;
}

 
}

 
Person的实体对象关系类为:
public class Person {

 
private int id;
 
private String name;
 
private IdCard idCard; //在这要持有身份证的引用。
 
public int getId() {
return id;
}

 
public void setId(int id) {
this.id = id;
}

 
public String getName() {
return name;
}

 
public void setName(String name) {
this.name = name;
}

 
public IdCard getIdCard() {
return idCard;
}

 
public void setIdCard(IdCard idCard) {
this.idCard = idCard;
}
 
 
}
第二步建立映射文件:
首先建立IdCard实体的映射文件,如下:
<hibernate-mapping>
<class name="com.bjsxt.hibernate.IdCard" table="t_idcard">
<id name="id">
<generator class="native"/>
</id>
<property name="cardNo"/>
</class>
</hibernate-mapping>
Person实体的映射文件,如下:
<hibernate-mapping>
<class name="com.bjsxt.hibernate.Person" table="t_person">
<id name="id">
<generator class="foreign">//因为要采用主键关联,这个主键要关联IdCard的主键,故这不能设为自增的,他的主键应该来源于IdCard,故                                                                 //为foreign,表示关联于外部。
<param name="property">idCard</param>//这个指定外部关联来源于谁,其中的name属性是固定的,都是property。
</generator>
</id>
<property name="name"/>
<one-to-one name="idCard" constrained="true"/>//这个表示hibernate怎么加载他的关联引用对象。name就是定义的属性。constrained这个属性表示加入了外键约束。需要设置为true,在一对一关系关联映射时需要添加这个属性,不加的话外键约束就不加上
</class>
</hibernate-mapping>

 
第三部建立hibernate.cfg.xml文件:如下:
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.url">jdbc:mysql://localhost/hibernate_one2one_pk_1</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">bjsxt</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.show_sql">true</property>
 
<mapping resource="com/bjsxt/hibernate/IdCard.hbm.xml"/>
<mapping resource="com/bjsxt/hibernate/Person.hbm.xml"/>
</session-factory>
</hibernate-configuration>

 
第四部写测试代码,以存储为例:
public class One2OneTest extends TestCase {

 
public void testSave1() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
 
IdCard idCard = new IdCard();
idCard.setCardNo("88888888888888");
 
Person person = new Person();
person.setName("菜10");
person.setIdCard(idCard);
 
//不会出现TransientObjectException异常
//因为一对一主键关联映射中,默认了cascade属性
session.save(person);
 
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
 
public void testLoad1() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
 
Person person = (Person)session.load(Person.class, 1);
System.out.println("person.name=" + person.getName());
System.out.println("idCard.cardNo=" + person.getIdCard().getCardNo());
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}

 
public void testLoad2() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
 
IdCard idCard = (IdCard)session.load(IdCard.class, 1);
System.out.println("idcard.cardNo=" + idCard.getCardNo());
System.out.println("idcard.person.name=" + idCard.getPerson().getName());
 
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
 
}

你可能感兴趣的:(Hibernate,职场,休闲,实体关联)