개발관련/Spring 2015. 12. 7. 12:01

이번엔 join에 대해 알아보자. join은 1:1 맵핑, 1:m, m:n 아마도 이렇게 구성이 될것이다. 

여기서는 1:1에 대해 알아보자. 


객체는 person과 personDetail 두가지가 있다. 그럼 코드를 보자. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package com.zest.hibernate.chapter6.onetoonemapping;
 
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
 
 
/**
 * 
 * one to one
 * ex) person data table
 * person id : 1
 *person name: aaaa
 *pdetail_fk :32768 이넘 
 *
 *person_detail
 *detailId_pk : 32768 이넘
 *income:123456786
 *job : adklja
 *zipcode : 20815
 *
 *위에 '이넘' 두개가 1:1로 맵핑. 
 */
@Entity
public class Person {
 
    @Id
    @GeneratedValue
    private int personId;
    private String personName;
    
    /**
     * CascadeType의 종류에는 다음과 같은 것들이 있다.
CascadeType.RESIST – 엔티티를 생성하고, 연관 엔티티를 추가하였을 때 persist() 를 수행하면 연관 엔티티도 함께 persist()가 수행된다.  만약 연관 엔티티가 DB에 등록된 키값을 가지고 있다면 detached entity passed to persist Exception이 발생한다.
CascadeType.MERGE – 트랜잭션이 종료되고 detach 상태에서 연관 엔티티를 추가하거나 변경된 이후에 부모 엔티티가 merge()를 수행하게 되면 변경사항이 적용된다.(연관 엔티티의 추가 및 수정 모두 반영됨)
CascadeType.REMOVE – 삭제 시 연관된 엔티티도 같이 삭제됨
CascadeType.DETACH – 부모 엔티티가 detach()를 수행하게 되면, 연관된 엔티티도 detach() 상태가 되어 변경사항이 반영되지 않는다.
CascadeType.ALL – 모든 Cascade 적용
fetch 의 순위 두 개 있다
fetch=FetchType.EAGER: 실행 문 바로 꺼냈다
fetch=FetchType.LAZY: 쓸 때 비로소 꺼냈다
     */
    @OneToOne(cascade=CascadeType.ALL, fetch= FetchType.EAGER)
    @JoinColumn(name="pDetail_FK")
    private PersonDetail pDetail;
    
    
    
    public PersonDetail getpDetail() {
        return pDetail;
    }
    public void setpDetail(PersonDetail pDetail) {
        this.pDetail = pDetail;
    }
    public int getPersonId() {
        return personId;
    }
    public void setPersonId(int personId) {
        this.personId = personId;
    }
    public String getPersonName() {
        return personName;
    }
    public void setPersonName(String personName) {
        this.personName = personName;
    }
    
}
 
cs


새로운 어노테이션이 등장한다. OneToOne 과 JoinColumn 이 추가 되었다. 

OneToOne의 경우 외래키를 만들때 선언하는 어노테이션이다. Cascade속성과 Fetch 속성 두가지를 지원한다. JoinColumn은 외래키가 되는 Column의 실제 Column이름을 지정하는것이다. 그냥 테이블 생성시에는 @Column이라는 놈이랑 비슷하다고 생각하면된다.  그리고 중요한 것은 기본키가 되는 객체에 어노테이션을 선언한다는것이다. 


그럼 personDetail을 만들어보자. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
 
package com.zest.hibernate.chapter6.onetoonemapping;
 
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
 
 
@Entity
public class PersonDetail {
 
    @Id
    @GeneratedValue
    @Column(name="detailId_PK")
    private int personDetailId;
    private String zipCode;
    private String job;
    private double income;
    
    
    
    public int getPersonDetailId() {
        return personDetailId;
    }
    public void setPersonDetailId(int personDetailId) {
        this.personDetailId = personDetailId;
    }
    public String getZipCode() {
        return zipCode;
    }
    public void setZipCode(String zipCode) {
        this.zipCode = zipCode;
    }
    public String getJob() {
        return job;
    }
    public void setJob(String job) {
        this.job = job;
    }
    public double getIncome() {
        return income;
    }
    public void setIncome(double income) {
        this.income = income;
    }
    
    
}
 
cs


기존 테이블을 만들던 코드와 똑같다. 테스트 코드 ㄱㄱ


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
 
package com.zest.hibernate.chapter6.onetoonemapping;
 
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.junit.Test;
 
import com.zest.hibernate.chapter5.inheritancemapping.Module;
import com.zest.hibernate.chapter5.inheritancemapping.Project;
import com.zest.hibernate.chapter5.inheritancemapping.Task;
 
public class OneToOneTest {
 
    @Test
    public void oneTest(){
        AnnotationConfiguration config = new AnnotationConfiguration();
        config.addAnnotatedClass(Person.class);
        config.addAnnotatedClass(PersonDetail.class);
        config.configure("hibernate.cfg.xml");
        
        new SchemaExport(config).create(truetrue);
 
        // 아래 두개의 구문은 객체를 트랜잭션을 컨트롤.
        SessionFactory factory = config.buildSessionFactory();
        Session session = factory.getCurrentSession();
 
        session.beginTransaction();
        
        PersonDetail alexDetail = new PersonDetail();
        alexDetail.setZipCode("20815");
        alexDetail.setJob("Accountant");
        alexDetail.setIncome(67245.56);
        
        Person alex = new Person();
        alex.setPersonName("alex berry");
        
        alex.setpDetail(alexDetail);
        
        session.save(alex);
        //session.save(alexdetail); 이건 안함. 카스케이드 라서 
        session.getTransaction().commit();
        
        
    }
}
 
cs


결과는 다음과 같다. 

1
2
3
 
Hibernate: insert into TESTSCHEMA.PersonDetail (income, job, zipCode, detailId_PK) values (?, ?, ?, ?)
Hibernate: insert into TESTSCHEMA.Person (pDetail_FK, personName, personId) values (?, ?, ?)
cs


테이블 구조를 보자. Person의 테이블을 살펴보면 PersonId는 기본키이며 pDetail_FK는 외래키로 생성이 될것이다. 여기까지 OneAndOne 설명을 마친다. 


posted by 제스트
:
개발관련/Spring 2015. 12. 7. 11:49

이번엔 상속 관계에 대해 알아보자. 

Project, Module, Task 이 3개 객체가 있다. 

최상위 객체는 Project이며, 그 자식으로 Module 이 있으며, Module의 자식으로 Task가 있다. 

먼저 소스를 보자. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 
package com.zest.hibernate.chapter5.inheritancemapping;
 
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
 
 
@Entity
//single table 실행시 stategy가 없는것과 동일한 결과를 볼수있다. 
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
 
//각 class마다 table이 생성되며, 하위 class들은 pk키를 기준으로 테이블이 생성된다. 
//또, 최상위 클래스는 pk와 하위 컬럼만 존재한다. 
//@Inheritance(strategy=InheritanceType.JOINED)
 
//class에 맞는 컬럼 값만 저장하며, pk는 최상위 클래스 값으로 중복되지 않은 값으로 저장된다. 
//@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public class Project {
 
    @Id
    @GeneratedValue
    private int projectId;
    private String projectName;
    
    
    public int getProjectId() {
        return projectId;
    }
    public void setProjectId(int projectId) {
        this.projectId = projectId;
    }
    public String getProjectName() {
        return projectName;
    }
    public void setProjectName(String projectName) {
        this.projectName = projectName;
    }
    
    
}
 
cs



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 
package com.zest.hibernate.chapter5.inheritancemapping;
 
import javax.persistence.Entity;
 
@Entity
public class Module extends Project{
 
    private String moduleName;
 
    public String getModuleName() {
        return moduleName;
    }
 
    public void setModuleName(String moduleName) {
        this.moduleName = moduleName;
    }
    
}
 
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
package com.zest.hibernate.chapter5.inheritancemapping;
 
import javax.persistence.Entity;
 
@Entity
public class Task extends Module{
 
    private String taskName;
 
    public String getTaskName() {
        return taskName;
    }
 
    public void setTaskName(String taskName) {
        this.taskName = taskName;
    }
    
    
}
 
cs


먼저 상속에 관한 옵션은 3가지 어노테이션이 존재한다. 

@Inheritance(strategy=InheritanceType.SINGLE_TABLE)  - 디폴트 선언이며, 하위 자식의 값들은 무시되며, 최상위 클래스의 테이블에만 정보를 넣는다. 

@Inheritance(strategy=InheritanceType.JOINED) - 이름에서 알듯이 자식들은 부모와 fk로 엮이며, 부모는 자식의 값을 가지고 있고, 자식은 자신의 값을 가지고 있는다. 결국 부모는 전체의 데이터를 가지고 있고 자식은 fk로 본인의 값들을 가지고 있는다. 

@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) - 부모 자식 포함해서 중복되지 않는 값을 서로간에 가지고 있는다. 


아마도 제일 많이 쓰이는건 2번이 아닐까 싶다. 그럼 테스트 코드를 보자. 먼저 @Inheritance(strategy=InheritanceType.SINGLE_TABLE)  일 경우 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
 
package com.zest.hibernate.chapter5.inheritancemapping;
 
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.junit.Test;
 
 
public class InheritaceMappingTest {
 
    @Test
    public void defaultRunTableTest(){
        AnnotationConfiguration config = new AnnotationConfiguration();
        config.addAnnotatedClass(Project.class);
        config.addAnnotatedClass(Module.class);
        config.addAnnotatedClass(Task.class);
        config.configure("hibernate.cfg.xml");
 
        new SchemaExport(config).create(truetrue);
 
        // 아래 두개의 구문은 객체를 트랜잭션을 컨트롤.
        SessionFactory factory = config.buildSessionFactory();
        Session session = factory.getCurrentSession();
 
        session.beginTransaction();
        
        Project p = new Project();
        p.setProjectName("hibernate lessons");
        
        Module m = new Module();
        m.setProjectName("spring lessons");
        m.setModuleName("aop");
        
        Task t = new Task();
        t.setProjectName("java lessons");
        t.setModuleName("collections");
        t.setTaskName("arraylist");
        
        session.save(p);
        session.save(m);
        session.save(t);
        
        session.getTransaction().commit();
    }
    
 
}
 
cs


1
2
3
4
 
Hibernate: insert into TESTSCHEMA.Project (projectName, DTYPE, projectId) values (?, 'Project', ?)
Hibernate: insert into TESTSCHEMA.Project (projectName, moduleName, DTYPE, projectId) values (?, ?, 'Module', ?)
Hibernate: insert into TESTSCHEMA.Project (projectName, moduleName, taskName, DTYPE, projectId) values (?, ?, ?, 'Task', ?)
cs


위의 형태로 로그가 나올 것이다. 결과를 보면 project 말고는 다른 테이블은 생성이 안될 것이다. 

1
2
3
4
drop table testschema.task;
drop table testschema.module;
drop table testschema.project;
 
cs


다시 테이블을 드랍 시키고 @Inheritance(strategy=InheritanceType.JOINED) 이 어노테이션을 적용해보자. 


1
2
3
4
5
6
7
 
Hibernate: insert into TESTSCHEMA.Project (projectName, projectId) values (?, ?)
Hibernate: insert into TESTSCHEMA.Project (projectName, projectId) values (?, ?)
Hibernate: insert into TESTSCHEMA.Module (moduleName, projectId) values (?, ?)
Hibernate: insert into TESTSCHEMA.Project (projectName, projectId) values (?, ?)
Hibernate: insert into TESTSCHEMA.Module (moduleName, projectId) values (?, ?)
Hibernate: insert into TESTSCHEMA.Task (taskName, projectId) values (?, ?)
cs

Project에는 결과가 총 3개가 생성이 된다. Module에 두개의 row가 생성되며, 마지막 task에는 1개의 row가 생성 될것이다. 그리고 테이블의 구조를 살펴보면 module.projectId , task.projectId는 pk,fk로 되어있다. 


마지막 @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)를 해보자. 먼저 테이블을 drop후 위에 선언한 project 객체의 주석을 변경한다. 그리고 테스트 ㄱㄱㄱㄱ


1
2
3
Hibernate: insert into TESTSCHEMA.Project (projectName, projectId) values (?, ?)
Hibernate: insert into TESTSCHEMA.Module (projectName, moduleName, projectId) values (?, ?, ?)
Hibernate: insert into TESTSCHEMA.Task (projectName, moduleName, taskName, projectId) values (?, ?, ?, ?)
cs


자신의 데이터만 row에 생길 것이다. 


소스는 https://github.com/zest133/hibernateTest.git 여기에




posted by 제스트
:
개발관련/Spring 2015. 12. 4. 17:22

이번엔 복합키에 대해 알아보자. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.zest.hibernate.chapter4;
 
import javax.persistence.Entity;
import javax.persistence.Id;
 
@Entity
public class Accounts {
 
    private int userId;
    private int accountId;
    
    
//    @Id
//    //만약 변수에 annotaion을 할꺼면 private는 안된다. 다른 객체이므로. getxxx 에 annotaion을 붙이면 된다. 
//    CompoundKey compoundKey;
    private int accountBalance;
    
    
//    public CompoundKey getCompoundKey() {
//        return compoundKey;
//    }
//    public void setCompoundKey(CompoundKey compoundKey) {
//        this.compoundKey = compoundKey;
//    }
    public int getAccountBalance() {
        return accountBalance;
    }
    public void setAccountBalance(int accountBalance) {
        this.accountBalance = accountBalance;
    }
    
    
}
 
cs


userId와 accountId에 복합키를 걸면 어떻게 할까? 


자 새로운 객체를 한개더 생성하자. 클래스 이름은 CompundKey이다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 
package com.zest.hibernate.chapter4;
 
import java.io.Serializable;
 
import javax.persistence.Embeddable;
 
//필히 Serializable 해줘야함. 
@Embeddable
public class CompoundKey implements Serializable{
 
    private int userId;
    private int accountId;
    
    public CompoundKey(int userId, int accountId){
        this.accountId = accountId;
        this.userId = userId;
    }
    
    public int getUserId() {
        return userId;
    }
    public void setUserId(int userId) {
        this.userId = userId;
    }
    public int getAccountId() {
        return accountId;
    }
    public void setAccountId(int accountId) {
        this.accountId = accountId;
    }
    
    
    
}
 
cs


여기서도 @Embeddable 이라는 어노테이션을 사용한다. 중요한 점은 필히 

Serializable을 해야하는 점이다. 그리고 Accounts 클래스를 수정하자. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 
package com.zest.hibernate.chapter4;
 
import javax.persistence.Entity;
import javax.persistence.Id;
 
@Entity
public class Accounts {
 
    //compound key로 옮겼으니 주석으로 막는다. 
//    private int userId;
//    private int accountId;
    
    
    @Id
    //만약 변수에 annotaion을 할꺼면 private는 안된다. 다른 객체이므로. getxxx 에 annotaion을 붙이면 된다. 
    CompoundKey compoundKey;
    private int accountBalance;
    
    
    public CompoundKey getCompoundKey() {
        return compoundKey;
    }
    public void setCompoundKey(CompoundKey compoundKey) {
        this.compoundKey = compoundKey;
    }
    public int getAccountBalance() {
        return accountBalance;
    }
    public void setAccountBalance(int accountBalance) {
        this.accountBalance = accountBalance;
    }
    
    
}
 
cs


CompoundKey라는 객체에 @Id 붙여 기본키를 만들었다. 다른 예제와 틀리게 private가 없을 것이다. 외부에 있는 변수를 끌어와서 private를 쓰면 에러가 난다. 이때 getxxx의 함수에 @Id를 붙이거나 또는 private 이상의 권한을 줘야만 된다. 


그럼 테스트 코드로... 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package com.zest.hibernate.chapter4;
 
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.junit.Test;
 
 
public class AccountTest {
 
    @Test
    public void account1() {
        AnnotationConfiguration config = new AnnotationConfiguration();
        config.addAnnotatedClass(Accounts.class);
        config.configure("hibernate.cfg.xml");
 
        new SchemaExport(config).create(truetrue);
 
        // 아래 두개의 구문은 객체를 트랜잭션을 컨트롤.
        SessionFactory factory = config.buildSessionFactory();
        Session session = factory.getCurrentSession();
 
        session.beginTransaction();
 
        CompoundKey key1 = new CompoundKey(10010001);
        Accounts savings = new Accounts();
        savings.setCompoundKey(key1);
        savings.setAccountBalance(8500);
        
        
        CompoundKey key2 = new CompoundKey(10020001);
        Accounts checking = new Accounts();
        checking.setCompoundKey(key2);
        checking.setAccountBalance(2500);
        
        
        session.save(savings);
        session.save(checking);
        session.getTransaction().commit();
    }
}
 
 
 
cs


index를 확인하면 userid와 accountid가 복합키로 생성되있을 것이다. 

posted by 제스트
: