Hibernate中的一对多关联技术

Hibernate中的一对多关联技术

【创建数据库脚本】

DROP TABLE IF EXISTS subitem;
DROP TABLE IF EXISTS item;

CREATE TABLE item(
    iid  INT PRIMARY KEY AUTO_INCREMENT,
    title  VARCHAR(50)
);

CREATE TABLE subitem(
    sid  INT PRIMARY KEY AUTO_INCREMENT,
    title  VARCHAR(50),
    iid  INT,
    CONSTRAINT fk_iid FOREIGN KEY(iid) REFERENCES item(iid) ON DELETE CASCADE
);

现在必须清楚以下关系:

  • 增加子表数据的时候要选择好与父表的关系。
  • 父表数据增加时要考虑子表数据的级联保存问题。

基于*.hbm.xml文件配置

【创建Item类】

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

@SuppressWarnings("serial")
public class Item implements Serializable {
    private int iid;
    private String title;
    private Set<Subitem> subitems = new HashSet<Subitem>();
    //方法略
}

【创建Subitem类】

import java.io.Serializable;

@SuppressWarnings("serial")
public class Subitem implements Serializable {
    private int sid;
    private String title;
    private Item item;
    //方法略
}

整个一对多关系主要是依靠Set集合。类定义完成后,关键是对*.hbm.xml文件的修改(一对多关系由一方控制多方)。
【创建Item.hbm.xml文件】

<hibernate-mapping>
    <class name="com.gub.vo.Item" table="item" schema="company">
        <id name="iid" column="iid"/>
        <property name="title" column="title"/>
        <!--inverse:控制反转-->
        <set name="subitems" cascade="all" fetch="select" >
            <!--关联的数据列-->
            <key>
                <column name="iid" />
            </key>
            <!--一对多所包含的数据类型-->
            <one-to-many class="com.gub.vo.Subitem"  />
        </set>
    </class>
</hibernate-mapping>

【创建Subitem.hbm.xml文件】

<hibernate-mapping>
    <class name="com.gub.vo.Subitem" table="subitem" schema="company">
        <id name="sid" column="sid"/>
        <property name="title" column="title"/>
        <!--多对一关系-->
        <many-to-one name="item" class="com.gub.vo.Item" fetch="select">
            <column name="iid" />
        </many-to-one>
    </class>
</hibernate-mapping>

【实现Item单表数据的增加】

public static void main(String[] args) {
        Item item = new Item();
        item.setIid(1);
        item.setTitle("类别1");
        HibernateSessionFactory.getSession().save(item);
        HibernateSessionFactory.getSession().beginTransaction().commit();
        HibernateSessionFactory.closeSession();
    }


【实现Item与Subitem数据的增加】

public static void main(String[] args) {
        Item item = new Item();
        item.setIid(1);
        item.setTitle("图书");
        for(int x=0;x<3;x++){
            Subitem subitem = new Subitem();
            subitem.setSid(x+1);
            subitem.setTitle("文学类-"+x);
            subitem.setItem(item);
            item.getSubitems().add(subitem);
            HibernateSessionFactory.getSession().evict(item);
        }
        HibernateSessionFactory.getSession().save(item);
        HibernateSessionFactory.getSession().beginTransaction().commit();
        HibernateSessionFactory.closeSession();
    }


观察控制台输出可以发现,Hibernate在进行一对多多表增加时有如下流程:

  • 查询要增加的子表数据是否存在,若数据不存在可以进行数据增加操作。
  • 增加父表数据,但此时并没有取得关联外键字段的内容。
  • 增加子表数据,但是由于没有取得关联外键字段的内容,所以将子表的与之关联的字段设为空值。
  • 更新子表,同步父表与子表的外键关联字段

之所以会造成这种情况,是因为父表没有把自己的控制权转交给子表(先增加主表,在增加子表,最后进行更新)。此时可以将父表的控制转交给子表(使用控制反转)。
【修改Item.hbm.xml文件】

<hibernate-mapping>
    <class name="com.gub.vo.Item" table="item" schema="company">
        <id name="iid" column="iid"/>
        <property name="title" column="title"/>
        <!--inverse:控制反转-->
        <set name="subitems" cascade="all"  inverse="true" >
            <!--关联的数据列-->
            <key>
                <column name="iid" />
            </key>
            <!--一对多所包含的数据类型-->
            <one-to-many class="com.gub.vo.Subitem"  />
        </set>
    </class>
</hibernate-mapping>

再次执行增加操作,观察控制台输出:

在进行子表数据增加的时候,利用控制反转相当于告诉了Hibernate,此时的父表中的数据不是有自己进行维护,而是由子表帮助进行维护,这样子表就可以直接处理父表的外键字段内容,就只会有增加数据的执行语句了。
【观察更新操作】

    public static void main(String[] args) {
        Item item = new Item();
        item.setIid(1);
        item.setTitle("HAHA");
        Subitem subitem = new Subitem();
        subitem.setItem(item);
        //subitem.setSid(1);
        subitem.setTitle("*******");
        item.getSubitems().add(subitem);
        HibernateSessionFactory.getSession().update(item);
        HibernateSessionFactory.getSession().beginTransaction().commit();
        HibernateSessionFactory.closeSession();
    }

如果我们为子表的sid字段设置内容,则直接对subitem表进行修改操作。

如果我们不是指sid字段的内容,则会在subitem表中新增一条数据。

【根据ID查询】

    public static void main(String[] args) {
        Item item = (Item)HibernateSessionFactory.getSession().get(Item.class,2);
        System.out.println("标题:"+item.getTitle());
        HibernateSessionFactory.closeSession();
    }

由于此时没有涉及到Subitem的任何内容,只查询item,可以直接查出。

    public static void main(String[] args) {
        Item item = (Item)HibernateSessionFactory.getSession().get(Item.class,2);
        System.out.println("标题:"+item.getTitle());
        System.out.println("栏目信息:"+item.getSubitems());
        HibernateSessionFactory.closeSession();
    }

此时发现出现了两条查询语句。

默认情况下,多方的数据不会自己进行加载,只有在调用与多方有关的数据时才会进行数据加载 。

    public static void main(String[] args) {
        Item item = (Item)HibernateSessionFactory.getSession().get(Item.class,2);
        System.out.println("标题:"+item.getTitle());
        HibernateSessionFactory.closeSession();
        System.out.println("栏目信息:"+item.getSubitems());
    }

若在多方加载之前关闭session连接,发现此时出现了异常信息,延时加载出现了问题(Hibernate的所有操作都要有session支持)。
修改Item.hbm.xml文件,将lazy设置为true,再次执行,f发现数据读取成功。

<hibernate-mapping>
<class name="com.gub.vo.Item" table="item" schema="company">
    <id name="iid" column="iid"/>
    <property name="title" column="title"/>
    <!--inverse:控制反转-->
    <set name="subitems" cascade="all"  inverse="true" fetch="select" lazy="true" >
        <!--关联的数据列-->
        <key>
            <column name="iid" />
        </key>
        <!--一对多所包含的数据类型-->
        <one-to-many class="com.gub.vo.Subitem"  />
    </set>
</class>
</hibernate-mapping>

基于Annotation的配置

在Item类的getSubitems()方法上加上如下注解:

    //配置了一对多的关系,设置了级联操作及延时加载
    @OneToMany(cascade = CascadeType.ALL,mappedBy = "item",fetch = FetchType.LAZY)
    public Set<Subitem> getSubitems() {
        return subitems;
    }

在Subitem类的getItem()方法上加上如下注解:

    //配置多对一关系,同时设置关联的数据列
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="iid")
    public Item getItem() {
        return item;
    }

此时配置完成,运行上面的所有测试程序,发现于hbm.xml文件配置结果一致。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值