hibernate Annotation 双向one2one

花了三天时间研究了下 hibernate Annotation 双向关联

主控方 Husband.java,主控方即 Husband 来负责维护 双向 one2one 之间的关系,在Husband.java 中必须添加 cascade ,否则保存报错。

package com.yazuo.entity.annotation.one2one;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

import org.hibernate.annotations.CascadeType;

@Entity
@Table(name="husband")
@SequenceGenerator(name="husband_id_seq",sequenceName="husband_id_seq",allocationSize=1)
public class Husband implements Serializable{

    /**
     *
     */
    private static final long serialVersionUID = 4920309776591073369L;
   
    @Id
    @GeneratedValue(generator="husband_id_seq",strategy=GenerationType.SEQUENCE)
    private Integer id;
   
    private String name;
   
    @OneToOne(cascade=javax.persistence.CascadeType.ALL)
    @JoinColumn(name="wife_id")

    private Wife wife;

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Wife getWife() {
        return wife;
    }

    public void setWife(Wife wife) {
        this.wife = wife;
    }

}
 

被控方 Wife.java

package com.yazuo.entity.annotation.one2one;

import java.io.Serializable;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

@Entity
@Table(name="wife")
@SequenceGenerator(name="wife_id_seq",sequenceName="wife_id_seq",allocationSize=1)
public class Wife implements Serializable{

    /**
     *
     */
    private static final long serialVersionUID = 8900644958432628054L;
   
    @Id
    @GeneratedValue(generator="wife_id_seq",strategy=GenerationType.SEQUENCE)
    private Integer id;
   
    private String name;
   
    /*
     * wife 端 加不加 fetch=FetchType.LAZY 打印的 sql 都是
     *  select
        husband0_.id as id2_1_,
        husband0_.name as name2_1_,
        husband0_.wife_id as wife3_2_1_,
        wife1_.id as id3_0_,
        wife1_.name as name3_0_
    from
        husband husband0_
    left outer join
        wife wife1_
            on husband0_.wife_id=wife1_.id
    where
        husband0_.wife_id=?
     */
    @OneToOne(mappedBy="wife")
    private Husband husband;

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Husband getHusband() {
        return husband;
    }

    public void setHusband(Husband husband) {
        this.husband = husband;
    }

}
 

Test.java

package com.yazuo.entity.annotation.one2one;

import org.hibernate.Hibernate;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.type.Type;


public class Test {

    @org.junit.Test
    public void add() throws Exception {
        //Configuration cfg = new  Configuration();
        /*
         * 使用注解时,hibernate.cfg.xml 中要添加 <mapping class="com.yazuo.annotation.entity">
         * 且 configuration 要使用 AnntationConfiguration,否则报
         * org.hibernate.MappingException: An AnnotationConfiguration instance is required to use <mapping class="com.yazuo.annotation.entity">
         */
        AnnotationConfiguration cfg = new AnnotationConfiguration();
        SessionFactory sf = cfg.configure().buildSessionFactory();
        Session session = sf.openSession();
       
        Wife wife = new Wife();
        wife.setName("wift");
       
        Husband husband = new Husband();
        husband.setName("husband");
       
        wife.setHusband(husband);
        husband.setWife(wife);
       
        session.save(husband);
        session.flush();
        session.close();
        sf.close();
    }
   
    @org.junit.Test
    public void findWifeById() throws Exception {
        /*
         * 在 wift 和 husband 两端加  fetch=FetchType.LAZY,都会打印两条 sql,一条是查询 wift,一条是查询 husband
         * 但 打印出来的 查询  husband 的 sql 不一样
         * lazy 加在 wife 端,打印的查询  husband sql :select from husband left outer join wife on
         *  lazy 加在 husband 端,打印的查询  husband sql :select from husband where wife_id = ?
         */
        AnnotationConfiguration cfg = new AnnotationConfiguration();
        SessionFactory sf = cfg.configure().buildSessionFactory();
        Session session = sf.openSession();
        String hql = "from Wife w where w.id = 17 ";
        Wife wife = (Wife) session.createQuery(hql).list().get(0);
        System.out.println(wife.getName());
        wife.getHusband().getName();
//        session.delete(wife);
        session.flush();
        session.close();
        sf.close();
    }
   
    @org.junit.Test
    public void findHusbandById() throws Exception {
        /*
         * 在 wift 和 husband 两端加  fetch=FetchType.LAZY,都会打印两条 sql,一条是查询 wift,一条是查询 husband
         * 但 打印出来的 查询  husband 的 sql 不一样
         * lazy 加在 wife 端,打印的查询  husband sql :select from husband left outer join wife on
         *  lazy 加在 husband 端,打印的查询  husband sql :select from husband where wife_id = ?
         */
        AnnotationConfiguration cfg = new AnnotationConfiguration();
        SessionFactory sf = cfg.configure().buildSessionFactory();
        Session session = sf.openSession();
        String hql = "from Husband h where h.id = 10";
        Husband husband = (Husband) session.createQuery(hql).uniqueResult();
        System.out.println(husband.getName());
        /*
         * 将 husband.wife 的 fetch=lazy 是,只有在调用husband.getWife()时候才会执行
         *  select
                wife0_.id as id3_1_,
                wife0_.name as name3_1_,
                husband1_.id as id2_0_,
                husband1_.name as name2_0_,
                husband1_.wife_id as wife3_2_0_
            from
                wife wife0_
            left outer join
                husband husband1_
                    on wife0_.id=husband1_.wife_id
            where
                wife0_.id=?
            否则只会打印一条查询 husband 的 sql
         */
        husband.getWife().getName();
        //session.delete(husband); //设置级联,会将husband.wife 一并删除
        //husband.getWife().setId(5);  改变 id 值报错
       
        session.flush();
        session.close();
        sf.close();
    }
   
    @org.junit.Test
    public void deleteWife() throws Exception {
        AnnotationConfiguration cfg = new AnnotationConfiguration();
        SessionFactory sf = cfg.configure().buildSessionFactory();
        Session session = sf.openSession();
//        String hql = "from Wife w where w.id = 3 ";
//        Wife wife = (Wife) session.createQuery(hql).list().get(0);
       
//        Wife wife = new Wife(); 不能删除瞬时态的 wife
//        wife.setId(4);    //违反完整约束条件 (QIAN.FK4BB1A83B38791291) - 已找到子记录
//        session.delete(wife); //wife 主键作为 husband 外键,不在wife 端设置 cascade 不能 delete
       
//        Query query = session.createQuery("delete from Wife w where w.id =? and name=?").setParameters(new Object[]{9,"wift"}, new Type[]{Hibernate.INTEGER,Hibernate.STRING});
//        Query query = session.createQuery("delete from Wife w where w.id in(:id)").setParameterList("id", new Integer[]{7,8});
        Query query = session.createQuery("delete from Wife w where w.id =:id").setParameter("id",4);
        query.executeUpdate();
//        session.createQuery("delete from Wife w where w.id = 5").executeUpdate();
        session.flush();
        session.close();
        sf.close();
    }
   
    @org.junit.Test
    public void deleteHusband() throws Exception {
        AnnotationConfiguration cfg = new AnnotationConfiguration();
        SessionFactory sf = cfg.configure().buildSessionFactory();
        Session session = sf.openSession();

        session.createQuery("delete from Husband h where h.id = 7").executeUpdate();
        session.flush();
        session.close();
        sf.close();
    }
   
    @org.junit.Test
    public void updateWife() throws Exception {
        AnnotationConfiguration cfg = new AnnotationConfiguration();
        SessionFactory sf = cfg.configure().buildSessionFactory();
        Session session = sf.openSession();
//        String hql = "update Wife w set w.id=? where w.name =?";
//        Query query = session.createQuery(hql).setParameters(new Object[]{17,"wift"}, new Type[]{Hibernate.INTEGER,Hibernate.STRING});
        String hql = "update Wife w set w.name =? where w.id=?";
        Query query = session.createQuery(hql).setParameters(new Object[]{"wife17",17}, new Type[]{Hibernate.STRING,Hibernate.INTEGER});
   
        query.executeUpdate();
        session.flush();
        session.close();
        sf.close();
    }
   
    @org.junit.Test
    public void updateHusband() throws Exception {
        AnnotationConfiguration cfg = new AnnotationConfiguration();
        SessionFactory sf = cfg.configure().buildSessionFactory();
        Session session = sf.openSession();
        String hql = "update Husband h set h.name =? where h.id=?";
        Query query = session.createQuery(hql).setParameters(new Object[]{"husband5",5}, new Type[]{Hibernate.STRING,Hibernate.INTEGER});
        query.executeUpdate();
        session.flush();
        session.close();
        sf.close();
    }
   
   
}
 

小结:

1.Husband 里面有 Wife 的 id,Husband 为 主表,Wife 为从表
所以 Wife 的 OneToOne(mappedBy="wife")

2.在 Husband 的 OneToOne 中添加 fetch=FetchType.LAZY ,执行  select * from husband h where h.id = ?
结果打印一条语句
  select
        husband0_.id as id2_,
        husband0_.name as name2_,
        husband0_.wife_id as wife3_2_
    from
        husband husband0_
    where
        husband0_.id=1
只有在显示的调用 husband.getWife().getName() 的时候才会执行
 select
        wife0_.id as id3_1_,
        wife0_.name as name3_1_,
        husband1_.id as id2_0_,
        husband1_.name as name2_0_,
        husband1_.wife_id as wife3_2_0_
    from
        wife wife0_
    left outer join
        husband husband1_
            on wife0_.id=husband1_.wife_id
    where
        wife0_.id=?
Hibernate:
    select
        wife0_.id as id3_1_,
        wife0_.name as name3_1_,
        husband1_.id as id2_0_,
        husband1_.name as name2_0_,
        husband1_.wife_id as wife3_2_0_
    from
        wife wife0_
    left outer join
        husband husband1_
            on wife0_.id=husband1_.wife_id
    where
        wife0_.id=?
       
 ================================
  select
        husband0_.id as id2_0_,
        husband0_.name as name2_0_,
        husband0_.wife_id as wife3_2_0_
    from
        husband husband0_
    where
        husband0_.wife_id=?
Hibernate:
    select
        husband0_.id as id2_0_,
        husband0_.name as name2_0_,
        husband0_.wife_id as wife3_2_0_
    from
        husband husband0_
    where
        husband0_.wife_id=?
结果是打印三条语句!!!!!!!!!
而在从表中加不加  fetch=FetchType.LAZY,结果都是打印两条  sql!!!!!

3.cascade=CascadeType.ALL 加那一边,那一边才有权利级联增加实体到数据库,可以在主从两端都加cascade=CascadeType.ALL
       
4.wife 主键作为 husband 外键,不在wife 端设置 cascade 不能 delete
设置 cascade此时会执行两条 sql ,先删除 husband ,再删除 wife

5.调用 session.delete(husband) 和执行  delete from Husband h where h.id = 7 效果不一样
前者会删除 husband.wife ,后者不会

================================================================
主控方和被控方的区别:
当主控方和被控方两端都不加 cascade
session.save(husband) 会报错,org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before

flushing: com.yazuo.entity.annotation.one2one.Wife

因为主控方有义务维持关系,却又不能级联增加被控方,可以 cascade="save-update,persist"。
而 session.save(wife) 不会报错

所以主控方必须加 cascade

 

你可能感兴趣的:(Hibernate,import,package,关系,Husband)