Hibernate的关联关系映射之一对多映射

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011301372/article/details/83146002

JavaWEB中一对多的设计及建表原则

导入SQL的建表语句

创建数据库:create database hibernate_day03

编写客户和联系人的JavaBean程序(注意一对多的编写规则)

客户的JavaBean如下

public class Customer {
    private Long cust_id;
    private String cust_name;
    private Long cust_user_id;
    private Long cust_create_id;
    private String cust_source;
    private String cust_industry;
    private String cust_level;
    private String cust_linkman;
    private String cust_phone;
    private String cust_mobile;
//hibernate框架默认的集合是set集合,集合必须要自己手动的初始化
	private Set<Linkman> linkmans = new HashSet<Linkman>();
}

联系人的JavaBean如下:

public class Linkman {

    private Long lkm_id;
    private String lkm_name;
    private String lkm_gender;
    private String lkm_phone;
    private String lkm_mobile;
    private String lkm_email;
    private String lkm_qq;
    private String lkm_position;
    private String lkm_memo;

//编写一个对象,不要自己new,
    private  Customer customer;
}

测试类

public class Demo1 {
    //双向关联的方式保存数据
    @Test
    public void run1(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tr = session.beginTransaction();
        //保存客户和联系人的数据
        Customer c1=new Customer();
        c1.setCust_name("美美");

        //创建两个联系人
        Linkman l1 = new Linkman();
        l1.setLkm_name("熊大");

        Linkman l2 = new Linkman();
        l2.setLkm_name("熊二");

        //演示双向关联
        c1.getLinkmans().add(l1);
        c1.getLinkmans().add(l2);

        l1.setCustomer(c1);
        l2.setCustomer(c1);

        //保存数据
        session.save(c1);
        session.save(l1);
        session.save(l2);

        tr.commit();

    }
}

级联保存

测试:如果代码只插入其中的一方的数据

  • 如果只保存其中的一方的数据,那么程序会抛出异常
  • 如果想完成只保存一方的数据,并且把相关联的数据都保存到数据库中,那么需要配置级联。
  • 级联保存是有方向性的。

级联保存的效果

  • 级联保存:保存一方同时可以把关联的对象也保存到数据库中
  • 使用 cascade = “save-update”
<!--在hibernate.hbm.xml中配置--> 
<!--cascade是级联属性-->
<set name="linkmans"  cascade="save-update">
        <!--需要的子标签-->
        <!--column外键的字段-->
        <key column="lkm_cust_id"></key>
        <one-to-many class="zst.cm.domain.Linkman"/>
    </set> 

级联问题

<!--Customer.hbm.xml-->
<set name = "linkmans" cascode="save-update">
	<key column = "lkm_cust_id"></key>
	<one-to-many class = "zst.cm.domain.Linkman"/>
</set> 


<!--Hibernate.hbm.xml-->
<many-to-one name="customer" class="zst.cm,domain.Customer" column="lkm_cust_id" />

测试代码

 public  void run3(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tr = session.beginTransaction();
        //保存客户和联系人的数据
        Customer c1=new Customer();
        c1.setCust_name("美美");

        //创建两个联系人
        Linkman l1 = new Linkman();
        l1.setLkm_name("熊大");
        //l1.setCustomer(c1);
        Linkman l2 = new Linkman();
        l2.setLkm_name("熊二");
        //l2.setCustomer(c1);
        //单向关联
        c1.getLinkmans().add(l1);
        c1.getLinkmans().add(l2);

      //保存数据
		session.save(c1);
    
        tr.commit();
    }

执行后会抛出异常

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column ‘lkm_cust_id’ cannot be null

修改配置后

<!--Customer.hbm.xml-->
  <set name="linkmans" inverse="true">
        <!--需要的子标签-->
        <!--column外键的字段-->
        <key column="lkm_cust_id"></key>
        <one-to-many class="zst.cm.domain.Linkman"/>
    </set>

<!--Linkman.hbm.xml-->
<many-to-one name="customer" class="zst.cm.domain.Customer" column="lkm_cust_id" cascade="save-update"/>

测试代码

 public  void run3(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tr = session.beginTransaction();
        //保存客户和联系人的数据
        Customer c1=new Customer();
        c1.setCust_name("美美");

        //创建两个联系人
        Linkman l1 = new Linkman();
        l1.setLkm_name("熊大");
        //l1.setCustomer(c1);
        Linkman l2 = new Linkman();
        l2.setLkm_name("熊二");
        //l2.setCustomer(c1);
        //单向关联
        c1.getLinkmans().add(l1);
        c1.getLinkmans().add(l2);

      //保存数据
		session.save(c1);
    
        tr.commit();
    } 

可以执行,但是真正保存到数据库中的内容是Customer的,而Linkman的数据并没有保存。

修改测试类

<!--Customer.hbm.xml-->
  <set name="linkmans" inverse="true">
        <!--需要的子标签-->
        <!--column外键的字段-->
        <key column="lkm_cust_id"></key>
        <one-to-many class="zst.cm.domain.Linkman"/>
    </set>

<!--Linkman.hbm.xml-->
<many-to-one name="customer" class="zst.cm.domain.Customer" column="lkm_cust_id" cascade="save-update"/>  
public  void run3(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tr = session.beginTransaction();
        //保存客户和联系人的数据
        Customer c1=new Customer();
        c1.setCust_name("关关");

        //创建两个联系人
        Linkman l1 = new Linkman();
        l1.setLkm_name("大黑");

        Linkman l2 = new Linkman();
        l2.setLkm_name("小黑");

  

       l1.setCustomer(c1);
        l2.setCustomer(c1);
        //保存数据
        session.save(l1);
        session.save(l2);
        tr.commit();
    } 

此时,关联成功,客户和联系人的 数据都保存。

级联删除

  • 在数据库中删除含有外键的客户的某个字段,SQL语句会报出错误。
    • delete from customers where cid =1;
  • 如果使用Hibernate框架直接删除客户的功能,测试发现是可以删除的
  • 上述的删除是普通的删除,那么也可以使用级联删除,注意:级联删除也是有方向性的。
    • <many-to-one cascade="delete"/>
public  void run4(){
    Session session = HibernateUtils.getCurrentSession();
    Transaction tr = session.beginTransaction();

    //查询1号客户
    //Linkman man= session.get(Linkman.class, 3L);
    Customer customer = session.get(Customer.class,20L);
    session.delete(customer);


    tr.commit();
} 
<!--customer.hbm.xml-->

 <set name="linkmans" inverse="true" cascade="delete">
        <!--需要的子标签-->
        <!--column外键的字段-->
        <key column="lkm_cust_id"></key>
        <one-to-many class="zst.cm.domain.Linkman" />
    </set>


<!--Linkman.hbm.xml-->
  <many-to-one name="customer" class="zst.cm.domain.Customer" column="lkm_cust_id" cascade="save-update" />

级联的取值(cascade的取值)和孤儿删除

  • none ----不使用级联
  • save-update ----级联保存或更新
  • delete----级联删除
  • delete-orphan----孤儿删除(注意:只能应用在一对多关系)
  • all----除了delete-orphan的所有情况(包含save-update delete)
  • all-delete-orphan----包含了delete-orphan 的所用情况(包含save-update delete delete-orphan)

孤儿删除(孤子删除),只用在一对多的环境下才有孤儿删除

  • 在一对多的关系中,可以将一的一方认为是父方,将多的一方认为是子方,孤儿删除:在解除看父子关系的时候,将子方记录就直接删除
  • <many-to-one cascade="delete-orphan">

解除关系

 public void run6(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tr = session.beginTransaction();

        //先获取到客户

        Customer  c1 = session.get(Customer.class ,25L);
        Linkman l1 = session.get(Linkman.class,6L);

        //解除
        Set<Linkman> linkmans = c1.getLinkmans();
        linkmans.remove(l1);
        tr.commit();

    }

让某一放放弃外键的维护,为多对多做准备

  • 先测试双方都维护外键的时候,会产生多余的SQL语句
    • 想修改客户和联系人的关系,进行双向关联,双方都会维护外键,会产生多余的SQL语句
    • 产生的原因:session的一级缓存中的快照机制,会让双方都更新数据库,产生了多余的SQL语句
  • 如果不想产生多余的SQL语句,那么需要一方来放弃外键的维护
    • <set>标签上配置一个inverse=“true”。true:放弃,false:不放弃,默认是false。
    • <inverse = "true">

cascade 和inverse的区别

  • cascade 用来级联操作(保存,修改和删除)
  • inverse用来维护外键的

猜你喜欢

转载自blog.csdn.net/u011301372/article/details/83146002
今日推荐