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

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

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

OneToMany-ManyToOne (관계 테이블 있을시)

 

OneToMany 관계에서 중간테이블이 있는 형태는 ManyToMany와동일한 관계이다.

 

OneToMany 관계를 만들기 위해 중간 관계 테이블 people_car pc_car_id unique 설정하였다.

 

people_car 컬럼명 접두사에 "PC_" 넣은 것은 관계 맵핑시 컬럼명을 정확히 구분하여 예제를 만들고 싶었던 이유다.

 

 

 

CREATE TABLE `people` (

  `PEOPLE_ID` int(11) NOT NULL AUTO_INCREMENT,

  `PEOPLE_NAME` varchar(45) NOT NULL,

  PRIMARY KEY (`PEOPLE_ID`)

) ENGINE=InnoDB AUTO_INCREMENT=205 DEFAULT CHARSET=utf8;

 

 

CREATE TABLE `people_car` (

  `PC_PEOPLE_ID` int(11) NOT NULL,

  `PC_CAR_ID` int(11) NOT NULL,

  PRIMARY KEY (`PC_PEOPLE_ID`,`PC_CAR_ID`),

  UNIQUE KEY `CAR_ID_UNIQUE` (`PC_CAR_ID`),

  KEY `fk_people_car_car_idx` (`PC_CAR_ID`),

  CONSTRAINT `fk_people_car_car` FOREIGN KEY (`PC_CAR_ID`) REFERENCES `car` (`CAR_ID`) ON DELETE CASCADE ON UPDATE CASCADE,

  CONSTRAINT `fk_people_car_people` FOREIGN KEY (`PC_PEOPLE_ID`) REFERENCES `people` (`PEOPLE_ID`) ON DELETE CASCADE ON UPDATE CASCADE

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

 

CREATE TABLE `car` (

  `CAR_ID` int(11) NOT NULL AUTO_INCREMENT,

  `CAR_NAME` varchar(45) DEFAULT NULL,

  PRIMARY KEY (`CAR_ID`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 



 

 

 

OneToMany-ManyToOne( Bidirectional(양방향) )

 

관계 테이블(people_car) 경우는 따로 접근하지 않을 경우는  맵핑하지 않아도 된다.

 

맵핑

People_Bi.java

package org.onecellboy.db.hibernate.table;

(생략..)

 

@Entity

@Table(name="people")

public class People_Bi {

 

        (생략..)

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

        private List<Car_Bi> cars = new LinkedList<Car_Bi>();

        

        

        

        

        public List<Car_Bi> getCars() {

                return cars;

        }

 

        public void setCars(List<Car_Bi> cars) {

                this.cars = cars;

        }

 

   (생략..)

        

        

        

        

}

 

 위에서 설명한 것과 동일하다.

 

 

 

Car_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.JoinTable;

import javax.persistence.ManyToOne;

import javax.persistence.Table;

 

@Entity

@Table(name="car")

public class Car_Bi {

 

        @Id

        @GeneratedValue(strategy=GenerationType.IDENTITY)

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

        private int id;

        

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

        private String name;

 

        

        @ManyToOne(fetch=FetchType.LAZY /*, cascade = CascadeType.ALL*/)

        @JoinTable(

                        name="people_car",

                        joinColumns= {@JoinColumn(name="PC_CAR_ID",referencedColumnName="CAR_ID")},

                        inverseJoinColumns= { @JoinColumn(name="PC_PEOPLE_ID",referencedColumnName="PEOPLE_ID")}

                        )

        private People_Bi people ;

        

        

        

        

        

        

        public People_Bi getPeople() {

                return people;

        }

 

        public void setPeople(People_Bi people) {

                this.people = people;

        }

 

        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;

        }

        

        

        

        

        

        

}

 

 

 

설명

@ManyToOne(fetch=FetchType.LAZY /*, cascade = CascadeType.ALL*/)

        @JoinTable(

                        name="people_car",

                        joinColumns= {@JoinColumn(name="PC_CAR_ID",referencedColumnName="CAR_ID")},

                        inverseJoinColumns= { @JoinColumn(name="PC_PEOPLE_ID",referencedColumnName="PEOPLE_ID")}

                        )

@ManyToOne : 다대일 관계라는 것이다.

@JoinTable : 관계 테이블로 조인되었다는 .
name :
관계 테이블명이다.
joinColumns : 조인 컬럼명 집합이다. 조인이 컬럼이 아닌 다수의 컬럼으로도 관계 있기 때문에 여러 JoinColumn 입력가능하다.


@JoinColumn(name="PC_CAR_ID",referencedColumnName="CAR_ID") : name 관계(Join) 테이블의 컬럼명이다. referencedColumnName 자신의 컬럼명이다. referencedColumnName 선언하지 않으면 디폴트로 Primary Key이다.  잠시 관계에 대해 생각해보자. 관계테이블(people_car) car 테이블을 참조한다. name( "PC_CAR_ID") referencedColumnName("CAR_ID") 참조한다. 라고 해석하라 했다.

 

inverseJoinColumns= { @JoinColumn(name="PC_PEOPLE_ID",referencedColumnName="PEOPLE_ID") : 관계(join) 테이블에서 반대 관계를 뜻한다. people 테이블과 people_car 테이블과의 관계이다. 여기도 마찬가지로 people_car 테이블이 people 테이블을 참조한다. name people_car 컬럼명, referencedColumnName people 테이블의 컬럼명이다.

 

 

 

 

 

 

 

 

 

테스트

테스트 코드

 

package org.onecellboy.db.hibernate;

 

import static org.junit.Assert.*;

 

import java.io.File;

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

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

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

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

 

public class OneToManyJoinTableBi {

        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;

                

                Session session =null;

                Transaction tx = null;

                

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

 

 

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

                

                session = sessionFactory.openSession();

                tx = session.beginTransaction();

                

                People_Bi people=new People_Bi();

                people.setName("조인");

                

                

                /*people car 이 서로가 서로를 설정하지 않으면 insert는 되는데 관계가 맺어 지지 않는다.(참조가 null이 된다.)*/

                Car_Bi car1 = new Car_Bi();

                car1.setName("아반떼");

                car1.setPeople(people);

                

                Car_Bi car2 = new Car_Bi();

                car2.setName("벤틀리");

                car2.setPeople(people);

                

                Car_Bi car3 = new Car_Bi();

                car3.setName("투싼");

                car3.setPeople(people);

                

                people.getCars().add(car1);

                people.getCars().add(car2);

                people.getCars().add(car3);

                

                

                session.save(people);

                

                test_id = people.getId();

                

                

 

                

                tx.commit();

                session.close();

                

        

                

                

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

                

                session = sessionFactory.openSession();

                tx = session.beginTransaction();

                

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

                

                Car_Bi car4 = new Car_Bi();

                car4.setName("마티즈");

                car4.setPeople(people);

                people.getCars().add(car4);

                

                tx.commit();

                session.close();

                

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

                System.out.println("-------People에서 car 하나 제거-------");

                session = sessionFactory.openSession();

                tx = session.beginTransaction();

                

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

                

                List<Car_Bi> cars = people2.getCars();

                System.out.println("car 삭제 전 car들 갯수 : "+cars.size());

                

                cars.remove(1);

                

                System.out.println("car 삭제 후 car들 갯수 : "+cars.size());

                

                

                

                tx.commit();

                session.close();

                

                

                

        }

 

}

 

 

 

주의: 부모(people) 자식(car) 설정( People.setCar() )하고 자식도 부모를 설정( Car.setPeople() ) , 양방향으로 설정해야 부모(people) Insert 자동으로 자식(Car) 저장된다. 한방향만 설정하면 관계가 만들어 지지 않는다. 관계 테이블에 어떠한 값도 입력되지 않는다.

 

 

 

 

결과

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

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

Hibernate: insert into people (PEOPLE_NAME) values (?)

Hibernate: insert into car (CAR_NAME) values (?)

Hibernate: insert into people_car (PC_PEOPLE_ID, PC_CAR_ID) values (?, ?)

Hibernate: insert into car (CAR_NAME) values (?)

Hibernate: insert into people_car (PC_PEOPLE_ID, PC_CAR_ID) values (?, ?)

Hibernate: insert into car (CAR_NAME) values (?)

Hibernate: insert into people_car (PC_PEOPLE_ID, PC_CAR_ID) values (?, ?)

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

Hibernate: select people_bi0_.PEOPLE_ID as PEOPLE_I1_1_0_, people_bi0_.PEOPLE_NAME as PEOPLE_N2_1_0_ from people people_bi0_ where people_bi0_.PEOPLE_ID=?

Hibernate: select people_inf0_.PEOPLE_INFO_ID as PEOPLE_I1_3_0_, people_inf0_.PEOPLE_INFO_AGE as PEOPLE_I2_3_0_, people_inf0_.PEOPLE_INFO_BIRTHDAY as PEOPLE_I3_3_0_ from people_info people_inf0_ where people_inf0_.PEOPLE_INFO_ID=?

Hibernate: insert into car (CAR_NAME) values (?)

Hibernate: insert into people_car (PC_PEOPLE_ID, PC_CAR_ID) values (?, ?)

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

-------People에서 car 하나 제거-------

Hibernate: select people_bi0_.PEOPLE_ID as PEOPLE_I1_1_0_, people_bi0_.PEOPLE_NAME as PEOPLE_N2_1_0_ from people people_bi0_ where people_bi0_.PEOPLE_ID=?

Hibernate: select people_inf0_.PEOPLE_INFO_ID as PEOPLE_I1_3_0_, people_inf0_.PEOPLE_INFO_AGE as PEOPLE_I2_3_0_, people_inf0_.PEOPLE_INFO_BIRTHDAY as PEOPLE_I3_3_0_ from people_info people_inf0_ where people_inf0_.PEOPLE_INFO_ID=?

Hibernate: select cars0_.PC_PEOPLE_ID as PC_PEOPL2_2_0_, cars0_.PC_CAR_ID as PC_CAR_I1_2_0_, car_bi1_.CAR_ID as CAR_ID1_0_1_, car_bi1_.CAR_NAME as CAR_NAME2_0_1_, car_bi1_1_.PC_PEOPLE_ID as PC_PEOPL2_2_1_ from people_car cars0_ inner join car car_bi1_ on cars0_.PC_CAR_ID=car_bi1_.CAR_ID left outer join DB_TEST.people_car car_bi1_1_ on car_bi1_.CAR_ID=car_bi1_1_.PC_CAR_ID where cars0_.PC_PEOPLE_ID=?

car 삭제 전 car들 갯수 : 4

car 삭제 후 car들 갯수 : 3

Hibernate: delete from people_car where PC_CAR_ID=?

Hibernate: delete from car where CAR_ID=?

 

 

설명

테스트코드

            Car_Bi car1 = new Car_Bi();

                car1.setName("아반떼");

                car1.setPeople(people);

                

                Car_Bi car2 = new Car_Bi();

                car2.setName("벤틀리");

                car2.setPeople(people);

                

                Car_Bi car3 = new Car_Bi();

                car3.setName("투싼");

                car3.setPeople(people);

                

                people.getCars().add(car1);

                people.getCars().add(car2);

                people.getCars().add(car3);

                

                

                session.save(people);

결과

Hibernate: insert into people (PEOPLE_NAME) values (?)

Hibernate: insert into car (CAR_NAME) values (?)

Hibernate: insert into people_car (PC_PEOPLE_ID, PC_CAR_ID) values (?, ?)

Hibernate: insert into car (CAR_NAME) values (?)

Hibernate: insert into people_car (PC_PEOPLE_ID, PC_CAR_ID) values (?, ?)

Hibernate: insert into car (CAR_NAME) values (?)

Hibernate: insert into people_car (PC_PEOPLE_ID, PC_CAR_ID) values (?, ?)

설명

양방향 관계이므로 서로가 서로를 설정하게 하였다. people save() people add() car들도 insert되고 people_car 관계테이블에도 관계가 insert된다.
이건다 cascade = CascadeType.ALL 옵션 때문이라는 것을 알아두자.

 

테스트코드

 

                Car_Bi car4 = new Car_Bi();

                car4.setName("마티즈");

                car4.setPeople(people);

                people.getCars().add(car4);

 

결과

Hibernate: select people_bi0_.PEOPLE_ID as PEOPLE_I1_1_0_, people_bi0_.PEOPLE_NAME as PEOPLE_N2_1_0_ from people people_bi0_ where people_bi0_.PEOPLE_ID=?

Hibernate: select people_inf0_.PEOPLE_INFO_ID as PEOPLE_I1_3_0_, people_inf0_.PEOPLE_INFO_AGE as PEOPLE_I2_3_0_, people_inf0_.PEOPLE_INFO_BIRTHDAY as PEOPLE_I3_3_0_ from people_info people_inf0_ where people_inf0_.PEOPLE_INFO_ID=?

Hibernate: insert into car (CAR_NAME) values (?)

Hibernate: insert into people_car (PC_PEOPLE_ID, PC_CAR_ID) values (?, ?)

설명

이미 존재 하는 people car 추가했다. 따로 save() update 없이 세션이 종료되는 시점에서 car insert되고 people_car 관계 테이블에 관계가 insert 된다.

 

 

테스트코드

List<Car_Bi> cars = people2.getCars();

                System.out.println("club 삭제 전 club들 갯수 : "+cars.size());

                

                cars.remove(1);

결과

Hibernate: delete from people_car where PC_CAR_ID=?

Hibernate: delete from car where CAR_ID=?

설명

session.close() 시점에 people에서 제거된 car 삭제 된다.
이것은 orphanRemoval=true 옵션 때문이라는 것을 기억하자. 만약 옵션이 없었다면 car 삭제 되지 않고 people_car 관계 테이블에서 관계만 삭제되었을 것이다.

 

 

 

 

 

 

 

 

 

OneToMany( Unidirectional(단방향) )

OneToMany에서 단방향시에는 그냥 읽기용으로 사용하는 것이 좋다.

자식 추가 양방향과 다르게 한쪽에서만 관계를 알고 있어서 불필요한 쿼리, 효율적이지 않은 쿼리가 남발된다.

 

 

OneToMany 관계 (people->peopel_car->car) People_Uni.java

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

import javax.persistence.OneToMany;

import javax.persistence.OneToOne;

import javax.persistence.Table;

 

 

@Entity

@Table(name="people")

public class People_Uni {

 

    (생략.......)

        

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

        @JoinTable(

                        name="people_car",

                        joinColumns= {@JoinColumn(name="PC_PEOPLE_ID",referencedColumnName="PEOPLE_ID")},

                        inverseJoinColumns= {@JoinColumn(name="PC_CAR_ID",referencedColumnName="CAR_ID")}

                        )

        private List<Car_Uni> cars = new LinkedList<Car_Uni>();

        

 

        (생략.......)

        

}

 

일반적인 OneToMany 관계이다.

people_car 테이블의 PC_PEOPLE_ID 컬럼이 people 테이블의 PEOPLE_ID 컬럼을 참조하고 반대방향으로는 people_car 테이블의 PC_CAR_ID 컬럼이 car 테이블의 CAR_ID 컬럼을 참조한다.

 

 

 

테스트

테스트 코드

package org.onecellboy.db.hibernate;

 

import static org.junit.Assert.*;

 

import java.io.File;

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

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

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

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

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

 

public class OneToManyJoinTableUni {

 

        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 testPeople() {

        int test_id;

                

                Session session =null;

                Transaction tx = null;

                

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

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

                session = sessionFactory.openSession();

                tx = session.beginTransaction();

                

                People_Uni people=new People_Uni();

                people.setName("아반떼");

                

                

                /*people car 이 서로가 서로를 설정하지 않으면 insert는 되는데 관계가 맺어 지지 않는다.(참조가 null이 된다.)*/

                Car_Uni car1 = new Car_Uni();

                car1.setName("스포츠카");

                

                Car_Uni car2 = new Car_Uni();

                car2.setName("포르쉐");

        

                

                Car_Uni car3 = new Car_Uni();

                car3.setName("다마스");

 

                

                people.getCars().add(car1);

                people.getCars().add(car2);

                people.getCars().add(car3);

                

                

                session.save(people);

                test_id = people.getId();

                

                

                tx.commit();

                session.close();

                

                

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

                

                session = sessionFactory.openSession();

                tx = session.beginTransaction();

                

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

                

                Car_Uni car4 = new Car_Uni();

                car4.setName("포터");

                people.getCars().add(car4);

                

                tx.commit();

                session.close();

                

                

                

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

                System.out.println("-------People에서 car 하나 제거-------");

                session = sessionFactory.openSession();

                tx = session.beginTransaction();

                

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

                

                List<Car_Uni> cars = people2.getCars();

                System.out.println("car 삭제 전 car들 갯수 : "+cars.size());

                

                cars.remove(1);

                

                

                tx.commit();

                session.close();

                

                

 

 

                

        }

        

 

}

 

 

주의: 위의 양방향 예제와 한부분이 다르다. Car 에서 People 설정하지 않는다.

 

 

결과

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

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

Hibernate: insert into people (PEOPLE_NAME) values (?)

Hibernate: insert into car (CAR_NAME) values (?)

Hibernate: insert into car (CAR_NAME) values (?)

Hibernate: insert into car (CAR_NAME) values (?)

Hibernate: insert into people_car (PC_PEOPLE_ID, PC_CAR_ID) values (?, ?)

Hibernate: insert into people_car (PC_PEOPLE_ID, PC_CAR_ID) values (?, ?)

Hibernate: insert into people_car (PC_PEOPLE_ID, PC_CAR_ID) values (?, ?)

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

Hibernate: select people_uni0_.PEOPLE_ID as PEOPLE_I1_1_0_, people_uni0_.PEOPLE_NAME as PEOPLE_N2_1_0_ from people people_uni0_ where people_uni0_.PEOPLE_ID=?

Hibernate: select cars0_.PC_PEOPLE_ID as PC_PEOPL2_2_0_, cars0_.PC_CAR_ID as PC_CAR_I1_2_0_, car_uni1_.CAR_ID as CAR_ID1_0_1_, car_uni1_.CAR_NAME as CAR_NAME2_0_1_, car_uni1_1_.PC_PEOPLE_ID as PC_PEOPL2_2_1_ from people_car cars0_ inner join car car_uni1_ on cars0_.PC_CAR_ID=car_uni1_.CAR_ID left outer join DB_TEST.people_car car_uni1_1_ on car_uni1_.CAR_ID=car_uni1_1_.PC_CAR_ID where cars0_.PC_PEOPLE_ID=?

Hibernate: insert into car (CAR_NAME) values (?)

Hibernate: delete from people_car where PC_PEOPLE_ID=?

Hibernate: insert into people_car (PC_PEOPLE_ID, PC_CAR_ID) values (?, ?)

Hibernate: insert into people_car (PC_PEOPLE_ID, PC_CAR_ID) values (?, ?)

Hibernate: insert into people_car (PC_PEOPLE_ID, PC_CAR_ID) values (?, ?)

Hibernate: insert into people_car (PC_PEOPLE_ID, PC_CAR_ID) values (?, ?)

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

-------People에서 car 하나 제거-------

Hibernate: select people_uni0_.PEOPLE_ID as PEOPLE_I1_1_0_, people_uni0_.PEOPLE_NAME as PEOPLE_N2_1_0_ from people people_uni0_ where people_uni0_.PEOPLE_ID=?

Hibernate: select cars0_.PC_PEOPLE_ID as PC_PEOPL2_2_0_, cars0_.PC_CAR_ID as PC_CAR_I1_2_0_, car_uni1_.CAR_ID as CAR_ID1_0_1_, car_uni1_.CAR_NAME as CAR_NAME2_0_1_, car_uni1_1_.PC_PEOPLE_ID as PC_PEOPL2_2_1_ from people_car cars0_ inner join car car_uni1_ on cars0_.PC_CAR_ID=car_uni1_.CAR_ID left outer join DB_TEST.people_car car_uni1_1_ on car_uni1_.CAR_ID=car_uni1_1_.PC_CAR_ID where cars0_.PC_PEOPLE_ID=?

car 삭제 전 car들 갯수 : 4

Hibernate: delete from people_car where PC_PEOPLE_ID=?

Hibernate: insert into people_car (PC_PEOPLE_ID, PC_CAR_ID) values (?, ?)

Hibernate: insert into people_car (PC_PEOPLE_ID, PC_CAR_ID) values (?, ?)

Hibernate: insert into people_car (PC_PEOPLE_ID, PC_CAR_ID) values (?, ?)

Hibernate: delete from people_car where PC_CAR_ID=?

Hibernate: delete from car where CAR_ID=?

 

 

 

다른 설명없다. 위의 OneToMany 양방향 관계처럼 people car 추가하고 save() people insert 되고 자동으로 car insert 된다. 또한 people car 추가하면 자동으로 추가된 car insert되고 중간 테이블인 people_car에도 관계가 insert된다. 삭제도 마찬가지이다.

 

하지만 효율성에서는 양방향과 매우 다르다. 테스트 결과를 보면 car 한개를 삭제했는데 관계테이블인 people_car에서 people 관계된 모든 관계를 삭제하고, 다시 people 연결된 car들의 관계를 people_car 추가한다.

특정 people에서 삭제된 car 관계만 삭제하면 되는데 비효율적이게도 해당 people 모든 관계(people_car) 삭제했다가 다시 추가한다. 이점에 주의하기 바란다.

 

 

 

 

 

 

 

ManyToOne( Unidirectional(단방향) )

이건 양방향에서 ManyToOne 동일한다.

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

import javax.persistence.ManyToOne;

import javax.persistence.Table;

 

@Entity

@Table(name="car")

public class Car_Uni {

 

        @Id

        @GeneratedValue(strategy=GenerationType.IDENTITY)

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

        private int id;

        

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

        private String name;

 

        @ManyToOne(fetch=FetchType.LAZY)

        @JoinTable(

                        name="people_car",

                        joinColumns= {@JoinColumn(name="PC_CAR_ID",referencedColumnName="CAR_ID")},

                        inverseJoinColumns= { @JoinColumn(name="PC_PEOPLE_ID",referencedColumnName="PEOPLE_ID")}

                        )

        private People_Uni people ;

        

        

        

        

        

        public People_Uni getPeople() {

                return people;

        }

/*

        public void setPeople(People_Uni people) {

                this.people = people;

        }

*/

        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;

        }

        

        

        

}

 

 

 

People에다가 car과의 관계를 설정하는게 논리상 맞기 때문에 위의 ManyToOne관계는 읽기 전용 관계로 사용하면 된다.

cascade=CascadeType.ALL 있을 경우 알아서 car save() insert 연결된 people 자동으로 insert 시킨다.

하지만 동일한 people,car끼리 people에서도 car 추가하고 car에서도 people 추가하는 경우 관계테이블에 동일한 관계가 두번 insert되므로 Duplicate 예외가 발생할 있다. 따라서 단방향에서는 ManyToOne 관계는 읽기 전용 관계로 사용하는 것이 좋다.

 

 

근데 생각해 보면 OneToMany 단방향시에 추가, 삭제에 대해 비효율적인 쿼리를 한단 말이지, ManyToOne 경우는 하나의 관계여서 비효율적이지 않을꺼라고 One 부모로 Many 자식으로 One Many와의 관계를 책임지는 것보다는 Many 부모로 One 자식으로 관계를 책임지는게 단방향에서는 효율적인 동작을 할꺼라 생각해..

 


반응형