프로그래밍n학습자료(2018~)/Hibernate

[Hibernate] 4. Hibernate(하이버네이트) 테이블 관계 - One To Many ( 중간 관계 테이블 없을 시)

단세포소년 2018. 3. 8. 16:54
반응형

OneToMany-ManyToOne (관계 테이블 없을 )

OneToMany ManyToOne 두가지 경우가 있다.

 

  1. 관계테이블 없음 : 관계테이블 없이 Many쪽에서 참조컬럼을 갖는 경우
  2. 관계테이블 있음 : One Many 연결해주는 중간 관계 테이블있고 중간 관계 테이블에서 Many 쪽이 참조 값이 Unique 경우

 

테이블간의 결합성을 없애려고 한다면 중간 관계테이블을 두는게 좋고 아니라면 중간 관계테이블 없이 하는 것이 좋다.

 

 

 

OneToMany 관계에서 조심해야 듯은 Many 너무 많은 갯수를 가진다면 성능상 부하가 엄청날 것이다. 예를 들어 게시판의 글쓴이와 글의 관계라고 해보자 글쓴이가 글이 엄청 많다면 문제가 생긴다. 이때는 OneToMany 관계맵핑 자체를 하면 안되고 HQL 통해서 잘라서 가져와야 한다.

 

 

CREATE TABLE `phone` (

  `phone_id` int(11) NOT NULL AUTO_INCREMENT,

  `phone_number` varchar(45) DEFAULT NULL,

  `phone_owner_id` int(11) DEFAULT NULL,

  PRIMARY KEY (`phone_id`),

  UNIQUE KEY `phone_number_UNIQUE` (`phone_number`),

  KEY `fk_people_phone_idx` (`phone_owner_id`),

  CONSTRAINT `if_people_phone` FOREIGN KEY (`phone_owner_id`) REFERENCES `people` (`PEOPLE_ID`) ON DELETE SET NULL ON UPDATE CASCADE

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

CREATE TABLE `people` (

  `PEOPLE_ID` int(11) NOT NULL AUTO_INCREMENT,

  `PEOPLE_NAME` varchar(45) NOT NULL,

  PRIMARY KEY (`PEOPLE_ID`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;



 

phone 테이블에 people 대한 참조값이 있는 경우이다.

 

 

OneToMany-ManyToOne ( Bi-directional(양방향) )

맵핑

People_Bi.java : People 테이블의 맵핑클래스이다. _Bi 양방향을 뜻한다.

package org.onecellboy.db.hibernate.table;

 

import java.util.LinkedList;

import java.util.List;

 

import javax.persistence.Basic;

import javax.persistence.CascadeType;

import javax.persistence.Column;

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.OneToMany;

import javax.persistence.OneToOne;

import javax.persistence.PrimaryKeyJoinColumn;

import javax.persistence.Table;

 

@Entity

@Table(name="people")

public class People_Bi {

 

        @Id

        @GeneratedValue(strategy=GenerationType.IDENTITY)

        @Column(name="PEOPLE_ID",columnDefinition="INT")

        private int id;

        

        @Column(name="PEOPLE_NAME",columnDefinition="VARCHAR(45)")

        private String name;

 

        

        @OneToOne(fetch=FetchType.LAZY,mappedBy="people", cascade = CascadeType.ALL)

        private People_Info_Bi people_Info;

        

        

        @OneToMany(fetch=FetchType.LAZY,mappedBy="owner_people", cascade = CascadeType.ALL,orphanRemoval=true)

        private List<Phone_Bi> phones = new LinkedList<Phone_Bi>();

        

        

        

        

        public List<Phone_Bi> getPhones() {

                return phones;

        }

 

        public void setPhones(List<Phone_Bi> phones) {

                this.phones = phones;

        }

 

        public People_Info_Bi getPeople_Info() {

                return people_Info;

        }

 

        public void setPeople_Info(People_Info_Bi people_Info) {

                this.people_Info = people_Info;

        }

 

        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;

        }

        

 

}

 

설명

@OneToMany(fetch=FetchType.LAZY,mappedBy="owner_people", cascade = CascadeType.ALL,orphanRemoval=true)

private List<Phone_Bi> phones = new LinkedList<Phone_Bi>();

fetch=FetchType.LAZY : Lazy Loading 하겠다는 것이다.


mappedBy="owner_people" : Phone_Bi 맵핑클래스의 owner_people 멤버변수 관계로 연결되어 있다.


cascade = CascadeType.ALL : People_Bi 맵핑클래스의 행동(삽입,업데이트,삭제) Phone_Bi 맵핑클래스도 동일하게 영향을 받겠다. People_Bi insert/delete 되면 연결된 Phone_Bi 자동 insert/delete 된다.


orphanRemoval=true : 고아가 , 부모가 사라진, phones.remove() 통해 제거된 자식(Phone) 자동으로 DB에서 없애준다. 저장이나 업데이트하지 않아도 remove 되는 순간 알아서 DB에서 Delete된다. 이걸 사용할 때는 자식이 부모 없이 절대 존재하지 않는 상황에서 쓰이면 된다.

위의 예제에서는 phone 소유자 없이는 존재하지 않는다라는 가정하에 관계를 만들었다.

 

 

 

 

 

Phone_Bi.java

package org.onecellboy.db.hibernate.table;

 

import javax.persistence.CascadeType;

import javax.persistence.Column;

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.ManyToOne;

import javax.persistence.MapsId;

import javax.persistence.Table;

 

import org.hibernate.annotations.GenericGenerator;

import org.hibernate.annotations.Parameter;

 

@Entity

@Table(name="phone")

public class Phone_Bi {

 

        @Id

        @GeneratedValue(strategy=GenerationType.IDENTITY)

        @Column(name="PHONE_ID",columnDefinition="INT")

        private int id;

        

        @Column(name="PHONE_NUMBER",columnDefinition="VARCHAR(45)")

        private String number;

        

        

        @Column(name="PHONE_OWNER_ID",columnDefinition="INT",insertable=false, updatable=false)

        private Integer owner_id;

 

        

        @ManyToOne(optional = false)

        @JoinColumn(name="PHONE_OWNER_ID",referencedColumnName="PEOPLE_ID" ,nullable=true)

        private People_Bi owner_people;

        

 

 

        public People_Bi getOwner_people() {

                return owner_people;

        }

 

        public void setOwner_people(People_Bi owner_people) {

                this.owner_people = owner_people;

        }

        

        

 

        public int getId() {

                return id;

        }

 

        public void setId(int id) {

                this.id = id;

        }

 

        public String getNumber() {

                return number;

        }

 

        public void setNumber(String number) {

                this.number = number;

        }

 

        public Integer getOwner_id() {

                return owner_id;

        }

 

        public void setOwner_id(Integer owner_id) {

                this.owner_id = owner_id;

        }

        

        

        

        

        

}

 

 

설명

@Column(name="PHONE_OWNER_ID",columnDefinition="INT",insertable=false, updatable=false)

private Integer owner_id;

name="PHONE_OWNER_ID": 맵핑된 컬럼명이다.
 

insertable=false, updatable=false : 값이 존재하냐면 PHONE_OWNER_ID값을 맵핑하는 변수가 owner_id owner_people 두개 존재한다. 말은 맵핑 변수 owner_id 혹은 관계 변수 owner_people 변경에 따라 phone 테이블의 PHONE_OWNER_ID 컬럼이 변경되는 것이다. 변경할 있는 관계가 두개 이기 때문에 둘중 하나는 READ ONLY 읽기만 가능하게 하여야 한다. 만약 옵션이 없다면 .....should be mapped with insert="false" update="false".... 이런 에러 메세지가 나온다.

 

@ManyToOne(optional = false)

@JoinColumn(name="PHONE_OWNER_ID",referencedColumnName="PEOPLE_ID")

private People_Bi owner_people;

"name referencedColumnName 참조한다." 라고 해석하자.
ManyToOne
관계는 Many One 참조하고 참조를 저장하는 foreign key Many 존재한다.
Phone 테이블의 PHONE_OWNER_ID 컬럼이 PEOPLE_ID 참조하는 것이다.

name
에는 phone 테이블의 컬럼명, referencedColumnName 에는 people 테이블의 컬럼명을 입력하면 된다.

 

 

 

hibernate.cfg.xml mapping 클래스를 지정한다.

생략...

<mapping class="org.onecellboy.db.hibernate.table.People_Bi"/>

<mapping class="org.onecellboy.db.hibernate.table.Phone_Bi"/>

생략...

 

 

 

 

테스트

테스트 코드

package org.onecellboy.db.hibernate;

 

import static org.junit.Assert.*;

 

import java.io.File;

import java.util.Date;

import java.util.LinkedList;

import java.util.List;

 

import org.hibernate.Session;

import org.hibernate.SessionFactory;

import org.hibernate.Transaction;

import org.hibernate.boot.MetadataSources;

import org.hibernate.boot.registry.StandardServiceRegistry;

import org.hibernate.boot.registry.StandardServiceRegistryBuilder;

import org.junit.After;

import org.junit.AfterClass;

import org.junit.BeforeClass;

import org.junit.FixMethodOrder;

import org.junit.Test;

import org.junit.runners.MethodSorters;

import org.onecellboy.db.hibernate.table.People_Bi;

import org.onecellboy.db.hibernate.table.People_Info_Bi;

import org.onecellboy.db.hibernate.table.Phone_Bi;

 

 

 

 

/*

 * Bi-directional OneToMany 양방향 1:N 관계 

 * */

@FixMethodOrder(MethodSorters.NAME_ASCENDING)

public class OneToManyBi {

 

        static SessionFactory sessionFactory = null;

        static StandardServiceRegistry registry = null;

 

        static int select_id = 0;

        

        

        @BeforeClass

        public static void setUp()

        {

                registry = new StandardServiceRegistryBuilder().configure(new File("./conf/hibernate/hibernate.cfg.xml"))

                                .build();

                                sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();

 

        }

        

        @AfterClass

        public static void setDown()

        {

                sessionFactory.close();

        }

        

        @After

        public void testAfter()

        {

                System.out.println();

                System.out.println();

        }

        

        

        

        @Test

        public void test01() {

                System.out.println("======Insert TEST======");

                

                int test_id=0;

                

                

                Session session = sessionFactory.openSession();

 

                Transaction tx = session.beginTransaction();

 

                People_Bi people = new People_Bi();

                people.setName("이린");

                

                List<Phone_Bi> phones = people.getPhones();

                

                

                

                Phone_Bi phone1=new Phone_Bi();

                phone1.setNumber("010-1111-1111");

                phone1.setOwner_people(people);

                

                

                Phone_Bi phone2=new Phone_Bi();

                phone2.setNumber("010-2222-2222");

                phone2.setOwner_people(people);

                

                Phone_Bi phone3=new Phone_Bi();

                phone3.setNumber("010-3333-333.");

            phone3.setOwner_people(people);

                

                phones.add(phone1);

                phones.add(phone2);

                phones.add(phone3);

        

                

                session.save(people);

                

               System.out.println("-------People insert 후에 phone 추가해 보기-------");

                   Phone_Bi phone4=new Phone_Bi();

                   phone4.setNumber("010-4444-4444");

                   phone4.setOwner_people(people);

                 phones.add(phone4);

 

 

                

                tx.commit();

                session.close();

                

                test_id = people.getId();

                

                System.out.println();

                System.out.println();

                

                System.out.println("======Select TEST======");

                

                session = sessionFactory.openSession();

                tx = session.beginTransaction();

                

                People_Bi people2 = session.get(People_Bi.class, test_id);

                System.out.println("people id : "+people2.getId());

                System.out.println("people name : "+people2.getName());

                

                for (Phone_Bi phone_Bi : people2.getPhones()) {

                        System.out.println("people id : "+phone_Bi.getId());

                        System.out.println("people number :"+phone_Bi.getNumber());

                        System.out.println("people owner id : "+phone_Bi.getOwner_id());

                }

                

                

                System.out.println();

                System.out.println();

                System.out.println("======Delete TEST======");

                

                

                session = sessionFactory.openSession();

                tx = session.beginTransaction();

                

                People_Bi people3 = session.get(People_Bi.class, test_id);

                

                List<Phone_Bi> phones3 = people3.getPhones();

                System.out.println(""+phones3.size());

                

                phones3.remove(1);

                

                

                tx.commit();

                session.close();

 

        }

 

}

 

 

 

 

결과

======Insert TEST======

Hibernate:

    insert

    into

        people

        (PEOPLE_NAME)

    values

        (?)

Hibernate:

    insert

    into

        phone

        (PHONE_NUMBER, PHONE_OWNER_ID)

    values

        (?, ?)

Hibernate:

    insert

    into

        phone

        (PHONE_NUMBER, PHONE_OWNER_ID)

    values

        (?, ?)

Hibernate:

    insert

    into

        phone

        (PHONE_NUMBER, PHONE_OWNER_ID)

    values

        (?, ?)

-------People insert 후에 phone 추가해 보기-------

Hibernate:

    insert

    into

        phone

        (PHONE_NUMBER, PHONE_OWNER_ID)

    values

        (?, ?)

 

 

======Select TEST======

Hibernate:

    select

        people_bi0_.PEOPLE_ID as PEOPLE_I1_0_0_,

        people_bi0_.PEOPLE_NAME as PEOPLE_N2_0_0_

    from

        people people_bi0_

    where

        people_bi0_.PEOPLE_ID=?

Hibernate:

    select

        people_inf0_.PEOPLE_INFO_ID as PEOPLE_I1_1_0_,

        people_inf0_.PEOPLE_INFO_AGE as PEOPLE_I2_1_0_,

        people_inf0_.PEOPLE_INFO_BIRTHDAY as PEOPLE_I3_1_0_

    from

        people_info people_inf0_

    where

        people_inf0_.PEOPLE_INFO_ID=?

people id : 119

people name : 이린

Hibernate:

    select

        phones0_.PHONE_OWNER_ID as PHONE_OW3_2_0_,

        phones0_.PHONE_ID as PHONE_ID1_2_0_,

        phones0_.PHONE_ID as PHONE_ID1_2_1_,

        phones0_.PHONE_NUMBER as PHONE_NU2_2_1_,

        phones0_.PHONE_OWNER_ID as PHONE_OW3_2_1_

    from

        phone phones0_

    where

        phones0_.PHONE_OWNER_ID=?

people id : 150

people number :010-1111-1111

people owner id : 119

people id : 151

people number :010-2222-2222

people owner id : 119

people id : 152

people number :010-3333-3333

people owner id : 119

people id : 153

people number :010-4444-4444

people owner id : 119

 

 

======Delete TEST======

Hibernate:

    select

        people_bi0_.PEOPLE_ID as PEOPLE_I1_0_0_,

        people_bi0_.PEOPLE_NAME as PEOPLE_N2_0_0_

    from

        people people_bi0_

    where

        people_bi0_.PEOPLE_ID=?

Hibernate:

    select

        people_inf0_.PEOPLE_INFO_ID as PEOPLE_I1_1_0_,

        people_inf0_.PEOPLE_INFO_AGE as PEOPLE_I2_1_0_,

        people_inf0_.PEOPLE_INFO_BIRTHDAY as PEOPLE_I3_1_0_

    from

        people_info people_inf0_

    where

        people_inf0_.PEOPLE_INFO_ID=?

Hibernate:

    select

        phones0_.PHONE_OWNER_ID as PHONE_OW3_2_0_,

        phones0_.PHONE_ID as PHONE_ID1_2_0_,

        phones0_.PHONE_ID as PHONE_ID1_2_1_,

        phones0_.PHONE_NUMBER as PHONE_NU2_2_1_,

        phones0_.PHONE_OWNER_ID as PHONE_OW3_2_1_

    from

        phone phones0_

    where

        phones0_.PHONE_OWNER_ID=?

4

Hibernate:

    delete

    from

        phone

    where

        PHONE_ID=?

 

 

 

 

설명

테스트코드

Phone_Bi phone1=new Phone_Bi();

phone1.setNumber("010-1111-1111");

phone1.setOwner_people(people);

 

phones.add(phone1);

phones.add(phone2);

phones.add(phone3);

 

session.save(people);

결과

Hibernate:

    insert

    into

        people

        (PEOPLE_NAME)

    values

        (?)

Hibernate:

    insert

    into

        phone

        (PHONE_NUMBER, PHONE_OWNER_ID)

    values

        (?, ?)

Hibernate:

    insert

    into

        phone

        (PHONE_NUMBER, PHONE_OWNER_ID)

    values

        (?, ?)

Hibernate:

    insert

    into

        phone

        (PHONE_NUMBER, PHONE_OWNER_ID)

    values

        (?, ?)

설명

양방향이기 때문에 서로가 서로를 설정해야한다. 

phone setOwner_people() 통해 people 설정해야하고 people list add 통해 설정해야한다.
 

people.Phones phone add() 해주고 people save()하면 phone 목록은 자동으로 DB insert된다.

 

 

테스트코드

System.out.println("-------People insert 후에 phone 추가해 보기-------");

                   Phone_Bi phone4=new Phone_Bi();

                   phone4.setNumber("010-4444-4444");

                   phone4.setOwner_people(people);

                 phones.add(phone4);

결과

-------People insert 후에 phone 추가해 보기-------

Hibernate:

    insert

    into

        phone

        (PHONE_NUMBER, PHONE_OWNER_ID)

    values

        (?, ?)

설명

people insert 후에 phone 추가해 보았다.

리스트에 add() 하는 것만으로도 add phone DB insert 된다.

 save(), update() 명령이 없어도 자동으로 수행된다.

 

 

 

테스트코드

phones3.remove(1);

결과

Hibernate:

    delete

    from

        phone

    where

        PHONE_ID=?

설명

리스트에서 phone 제거하면 바로 Delete 쿼리가 발생한다. saveOrUpdate()이런 필요가 없다.
이것은 orphanRemoval=true 옵션 때문이다.

 

 

 

 

 

 

 

 

OneToMany-ManyToOne ( Unidirectional(방향) )

맵핑

 

People -> Phone

package org.onecellboy.db.hibernate.table;

 

import java.util.LinkedList;

import java.util.List;

 

import javax.persistence.CascadeType;

 

import javax.persistence.Column;

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.OneToMany;

import javax.persistence.OneToOne;

import javax.persistence.Table;

 

 

@Entity

@Table(name="people")

public class People_Uni {

        @Id

        @GeneratedValue(strategy=GenerationType.IDENTITY)

        @Column(name="PEOPLE_ID",columnDefinition="INT")

        private int id;

        

        @Column(name="PEOPLE_NAME",columnDefinition="VARCHAR(45)")

        private String name;

 

        

        @OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL,orphanRemoval=true)

        @JoinColumn(name="PHONE_OWNER_ID",referencedColumnName="PEOPLE_ID")

        private List<Phone_Uni> phones = new LinkedList<Phone_Uni>();

 

 

        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 List<Phone_Uni> getPhones() {

                return phones;

        }

 

 

        public void setPhones(List<Phone_Uni> phones) {

                this.phones = phones;

        }

        

 

}

 

설명

@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL,orphanRemoval=true)

@JoinColumn(name="PHONE_OWNER_ID",referencedColumnName="PEOPLE_ID")

Lazy 로딩, Cascade All, orphanRemoval 옵션을 주었다.
해당 옵션들은 위해서 설명하였다.
 

OneToMany 대해 생각해봐야한다.
One To Many
에서 참조값을 갖는 테이블은  Many 쪽이다. 다시 말해, Phone 테이블이 People 대한 참조값을 가진다는 것이다.

JoinColumn
에서 "name" "referencedColumnName" 참조한다고 했다. 여기서 보면 name에는 Phone 테이블의 참조하는 컬럼명과 referencedColumnName 에는 People 테이블의 참조된 컬럼명을 넣어야 한다.


@JoinColumn
name="PHONE_OWNER_ID" : People 테이블의 컬럼명이다.
referencedColumnName="PEOPLE_ID" : "PHONE_OWNER_ID" 참조하는 Phone 테이블의 컬럼명이다.

 

 

테스트

테스트코드

import static org.junit.Assert.*;

 

import java.io.File;

 

import org.hibernate.Session;

import org.hibernate.SessionFactory;

import org.hibernate.Transaction;

import org.hibernate.boot.MetadataSources;

import org.hibernate.boot.registry.StandardServiceRegistry;

import org.hibernate.boot.registry.StandardServiceRegistryBuilder;

import org.junit.After;

import org.junit.AfterClass;

import org.junit.BeforeClass;

import org.junit.Test;

import org.onecellboy.db.hibernate.table.People_Uni;

import org.onecellboy.db.hibernate.table.Phone_Uni;

 

public class OneToManyUni {

 

        static SessionFactory sessionFactory = null;

        static StandardServiceRegistry registry = null;

 

        static int select_id = 0;

        

        

        @BeforeClass

        public static void setUp()

        {

                registry = new StandardServiceRegistryBuilder().configure(new File("./conf/hibernate/hibernate.cfg.xml"))

                                .build();

                                sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();

 

        }

        

        @AfterClass

        public static void setDown()

        {

                sessionFactory.close();

        }

        

        @After

        public void testAfter()

        {

                System.out.println();

                System.out.println();

        }

        

        @Test

        public void test() {

        

                int test_id=0;

                

                Session session =null;

                Transaction tx = null;

                

                

                System.out.println("======People Insert People에 포함된 Phone도 자동 Insert======");

                

                session = sessionFactory.openSession();

                tx = session.beginTransaction();

                

                People_Uni people = new People_Uni();

                people.setName("단소");

                

                

                Phone_Uni phone1 = new Phone_Uni();

                phone1.setNumber("111-1111-1111");

                

                Phone_Uni phone2 = new Phone_Uni();

                phone2.setNumber("222-2222-2222");

                

                Phone_Uni phone3 = new Phone_Uni();

                phone3.setNumber("333-3333-3333");

                

                

                people.getPhones().add(phone1);

                people.getPhones().add(phone2);

                people.getPhones().add(phone3);

                

                session.saveOrUpdate(people);

                

                test_id = people.getId();

                

                try {

                        Thread.sleep(100);

                } catch (InterruptedException e) {

                        // TODO Auto-generated catch block

                        e.printStackTrace();

                }

                

                tx.commit();

                session.close();

                

                

                System.out.println("======이미 Insert People  Phone을 추가시켰을때 자동 Insert======");

                session = sessionFactory.openSession();

                tx = session.beginTransaction();

                

                People_Uni people2 = session.get(People_Uni.class, test_id);

                

                

                Phone_Uni phone4 = new Phone_Uni();

                phone4.setNumber("444-444-4444");

                

                people2.getPhones().add(phone4);

                

                tx.commit();

                session.close();

                

                

                System.out.println("======Insert People에 서 Phone을 제거시켰을때 자동 Delete======");

                session = sessionFactory.openSession();

                tx = session.beginTransaction();

                

                People_Uni people3 = session.get(People_Uni.class, test_id);

                

                people3.getPhones().remove(1);

                

                tx.commit();

                session.close();

                

                

        }

 

}

 

 

결과

======People Insert People에 포함된 Phone도 자동 Insert======

Hibernate:

    insert

    into

        people

        (PEOPLE_NAME)

    values

        (?)

Hibernate:

    insert

    into

        phone

        (PHONE_NUMBER, PHONE_OWNER_ID)

    values

        (?, ?)

Hibernate:

    insert

    into

        phone

        (PHONE_NUMBER, PHONE_OWNER_ID)

    values

        (?, ?)

Hibernate:

    insert

    into

        phone

        (PHONE_NUMBER, PHONE_OWNER_ID)

    values

        (?, ?)

Hibernate:

    update

        phone

    set

        PHONE_OWNER_ID=?

    where

        PHONE_ID=?

Hibernate:

    update

        phone

    set

        PHONE_OWNER_ID=?

    where

        PHONE_ID=?

Hibernate:

    update

        phone

    set

        PHONE_OWNER_ID=?

    where

        PHONE_ID=?

======이미 Insert People  Phone을 추가시켰을때 자동 Insert======

Hibernate:

    select

        people_uni0_.PEOPLE_ID as PEOPLE_I1_0_0_,

        people_uni0_.PEOPLE_NAME as PEOPLE_N2_0_0_

    from

        people people_uni0_

    where

        people_uni0_.PEOPLE_ID=?

Hibernate:

    select

        phones0_.PHONE_OWNER_ID as PHONE_OW3_2_0_,

        phones0_.PHONE_ID as PHONE_ID1_2_0_,

        phones0_.PHONE_ID as PHONE_ID1_2_1_,

        phones0_.PHONE_NUMBER as PHONE_NU2_2_1_,

        phones0_.PHONE_OWNER_ID as PHONE_OW3_2_1_

    from

        phone phones0_

    where

        phones0_.PHONE_OWNER_ID=?

Hibernate:

    insert

    into

        phone

        (PHONE_NUMBER, PHONE_OWNER_ID)

    values

        (?, ?)

Hibernate:

    update

        phone

    set

        PHONE_OWNER_ID=?

    where

        PHONE_ID=?

======Insert People에 서 Phone을 제거시켰을때 자동 Delete======

Hibernate:

    select

        people_uni0_.PEOPLE_ID as PEOPLE_I1_0_0_,

        people_uni0_.PEOPLE_NAME as PEOPLE_N2_0_0_

    from

        people people_uni0_

    where

        people_uni0_.PEOPLE_ID=?

Hibernate:

    select

        phones0_.PHONE_OWNER_ID as PHONE_OW3_2_0_,

        phones0_.PHONE_ID as PHONE_ID1_2_0_,

        phones0_.PHONE_ID as PHONE_ID1_2_1_,

        phones0_.PHONE_NUMBER as PHONE_NU2_2_1_,

        phones0_.PHONE_OWNER_ID as PHONE_OW3_2_1_

    from

        phone phones0_

    where

        phones0_.PHONE_OWNER_ID=?

Hibernate:

    update

        phone

    set

        PHONE_OWNER_ID=null

    where

        PHONE_OWNER_ID=?

        and PHONE_ID=?

Hibernate:

    delete

    from

        phone

    where

        PHONE_ID=?

 

 

 

 

설명

테스트코드

        People_Uni people = new People_Uni();

        people.setName("단소");

                

                

        Phone_Uni phone1 = new Phone_Uni();

        phone1.setNumber("111-1111-1111");

                

        Phone_Uni phone2 = new Phone_Uni();

        phone2.setNumber("222-2222-2222");

        

        Phone_Uni phone3 = new Phone_Uni();

        phone3.setNumber("333-3333-3333");

        

        

        people.getPhones().add(phone1);

        people.getPhones().add(phone2);

        people.getPhones().add(phone3);

        

        session.saveOrUpdate(people);

결과

Hibernate:

    insert

    into

        people

        (PEOPLE_NAME)

    values

        (?)

Hibernate:

    insert

    into

        phone

        (PHONE_NUMBER, PHONE_OWNER_ID)

    values

        (?, ?)

Hibernate:

    insert

    into

        phone

        (PHONE_NUMBER, PHONE_OWNER_ID)

    values

        (?, ?)

Hibernate:

    insert

    into

        phone

        (PHONE_NUMBER, PHONE_OWNER_ID)

    values

        (?, ?)

Hibernate:

    update

        phone

    set

        PHONE_OWNER_ID=?

    where

        PHONE_ID=?

Hibernate:

    update

        phone

    set

        PHONE_OWNER_ID=?

    where

        PHONE_ID=?

Hibernate:

    update

        phone

    set

        PHONE_OWNER_ID=?

    where

        PHONE_ID=?

설명

people phone add 시키고 people save()시키면 자동 people add phone 자동으로 insert 되었다.

눈여겨 점은  people insert 되고 다음 phone insert people primary key 값으로 phone "PHONE_OWER_ID" 컬럼값을 update 시켰다는 것이다.

 

양방향과 다르게 people 에서 phone으로의 단방향 관계에서는 phone people 대해 없기 때문에 초기에는 "PHONE_OWNER_ID" 값에 null 주고 그다음 update 통해 참조값을 넣는다.


만약
phone "PHONE_OWNER_ID" 컬럼이 Not Null 이었다면 에러가 발생했을 것이다.

 

있는 것은 1:N 관계는 무조건 서로 관계 되어야 하므로 양방향이 좋고

[0~1]:N 관계는 관계가 없을 있는 상태라 단방향이 좋다.

 

 

 

테스트코드

        People_Uni people2 = session.get(People_Uni.class, test_id);

                

                

        Phone_Uni phone4 = new Phone_Uni();

        phone4.setNumber("444-444-4444");

                

        people2.getPhones().add(phone4);

결과

Hibernate:

    select

        people_uni0_.PEOPLE_ID as PEOPLE_I1_0_0_,

        people_uni0_.PEOPLE_NAME as PEOPLE_N2_0_0_

    from

        people people_uni0_

    where

        people_uni0_.PEOPLE_ID=?

Hibernate:

    select

        phones0_.PHONE_OWNER_ID as PHONE_OW3_2_0_,

        phones0_.PHONE_ID as PHONE_ID1_2_0_,

        phones0_.PHONE_ID as PHONE_ID1_2_1_,

        phones0_.PHONE_NUMBER as PHONE_NU2_2_1_,

        phones0_.PHONE_OWNER_ID as PHONE_OW3_2_1_

    from

        phone phones0_

    where

        phones0_.PHONE_OWNER_ID=?

Hibernate:

    insert

    into

        phone

        (PHONE_NUMBER, PHONE_OWNER_ID)

    values

        (?, ?)

Hibernate:

    update

        phone

    set

        PHONE_OWNER_ID=?

    where

        PHONE_ID=?

설명

이미 존재하는 People select 하고 phone add() 하면 자동으로 phone insert 된다.

위에서 마찬가지로 phone people 모르므로 insert update 통해 "PHONE_OWNER_ID" 갱신한다.

 

 

 

테스트코드

        People_Uni people3 = session.get(People_Uni.class, test_id);

                

        people3.getPhones().remove(1);

결과

Hibernate:

    delete

    from

        phone

    where

        PHONE_ID=?

설명

이제 설명하기도 입아프다. orphanRemoval=true 때문에 부모(people) 잃은 자식(phone) 삭제된다.

만약에  orphanRemoval=false 라면 어떻게 될까? 그때는 부모를 잃은 자식은 삭제되는 것이 아니라. 부모로의 참조값이 null 되도록 update된다.

Hibernate:

    update

        phone

    set

        PHONE_OWNER_ID=null

    where

        PHONE_OWNER_ID=?

        and PHONE_ID=?


반응형