반응형

build.gradle 설정

// querydsl 추가
buildscript {
    ext {
        queryDslVersion = "5.0.0"
    }
}

plugins {
    id 'org.springframework.boot' version '2.6.4'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    
    //querydsl 플러그인 추가
    id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"

    id 'java'
}

group = 'com.study'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
    annotationProcessor 'org.projectlombok:lombok'

    implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.8'

    //querydsl 추가
    implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"
    implementation "com.querydsl:querydsl-apt:${queryDslVersion}"

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}


tasks.named('test') {
    useJUnitPlatform()
}

//querydsl 추가 시작
def querydslDir = "$buildDir/generated/querydsl"

querydsl {
    jpa = true
    querydslSourcesDir = querydslDir
}
sourceSets {
    main.java.srcDir querydslDir
}
compileQuerydsl{
    options.annotationProcessorPath = configurations.querydsl
}
configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
    querydsl.extendsFrom compileClasspath
}
//querydsl 추가 끝

 

반응형
반응형

엔티티(Entity) 설계 시 주의사항

1. Setter를 사용하지 말 것

Setter가 모두 열려있을 경우 변경 포인트가 많아서 유지 보수가 어려워집니다.

 

2. 모든 연관 관계는 지연로딩(LAZY)로 설정할 것 * 중요

즉시로딩(EAGER)은 예측이 어렵고 어떤 SQL이 실행될 지 예측하기 어렵습니다. 특히 JPQL을 실행할 때 N+1 문제가 자주 발생하게 됩니다.

 

3. 컬렉션은 필드에서 초기화할 것

컬렉션은 필드에서 바로 초기화해야 NullPointerException으로부터 안전합니다.

반응형
반응형

persistence.xml 설정

resources 디렉토리 밑에 META-INF 디렉토리를 생성하고 그 안에 persistence.xml을 만든 다음 아래 내용을 자신의 개발 환경에 맞게 세팅하시면 됩니다.

 

<?xml version="1.0" encoding="UTF-8" ?>
<persistence version="2.2"
             xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/">
    
    <!-- EntityManagerFactory 생성 시 unit name과 일치해야 합니다 -->
    <persistence-unit name="hello">
        <properties>
            <!-- 필수 속성 -->
            <!-- DB Driver -->
            <property name="javax.persistence.jdbc.driver" value="org.mariadb.jdbc.Driver"/>
            
            <!-- DB user info -->
            <property name="javax.persistence.jdbc.user" value="user"/>
            <property name="javax.persistence.jdbc.password" value="password"/>
            
            <!-- DB url -->
            <property name="javax.persistence.jdbc.url" value="jdbc:mariadb://localhost:3306/schema"/>
            
            <!-- DB Dialect 설정 -->
            <property name="hibernate.dialect" value="org.hibernate.dialect.MariaDB103Dialect"/>
            
            <!-- 옵션 -->
            <!-- SQL show -->
            <property name="hibernate.show_sql" value="true"/>
            
            <!-- SQL 정렬 -->
            <property name="hibernate.format_sql" value="true"/>
            
            <!-- SQL에 관한 주석 처리 -->
            <property name="hibernate.use_sql_comments" value="true"/>
            
            <!-- application 실행 시 ddl 전략 -->
            <property name="hibernate.hbm2ddl.auto" value="create"/>
        </properties>
        
    </persistence-unit>
</persistence>
반응형
반응형

연관 관계 편의 메소드를 사용하기 전에

이 부분을 이해하시려면 우선 영속성 컨텍스트(Persistence Context)에 대한 이해가 필요합니다. 관련 글은 다른 블로그에 자세히 설명된 게 있어서 링크로 첨부하니 확인해보세요!

 

JPA / 영속성 컨텍스트 / 1차 캐시 / 쓰기 지연

"T아카데미 / JPA 프로그래밍 기본기 다지기 - 김영한 " 강좌를 듣고 정리한 글입니다. 영속성 컨텍스트를 영속성 컨텍스로 관리하면 어떤 이점을 갖을까 1. 1차 캐시 / 엔티티 동일성 보장 2. 쓰기

www.ecsimsw.com

 

연관 관계 편의 메소드

JPA에서 양방향 연관 관계를 설정했을 때 연관 관계의 주인의 반대쪽 필드는 mappedby를 설정하여 읽기 전용으로 쓰게 됩니다. 그런데 일대다 중 다 쪽에만 연관 관계를 설정하면 객체 지향적이지 않을뿐더러 DB에서 데이터를 조회하기 전까지는 일대다 중 다 쪽에만 값이 세팅되어 일 쪽 Entity에서는 연관 관계를 모르기 때문에 일 쪽의 값을 출력해보면 데이터가 나오지 않습니다.

 

예제 코드

아래 코드는 teamA를 생성하고 memberA에 teamA를 넣어 연관 관계를 설정하는 코드입니다. 이 코드는 문제가 없어보일 수 있지만 실행하면 마지막 줄은 출력되지 않습니다.

 

memberA에는 teamA가 들어갔지만 반대인 teamA는 memberA와의 연관 관계가 설정되지 않았기 때문에 teamA에는 member와 관련된 아무런 값도 설정되지 않았기 때문입니다.

 

따라서 teamA가 memberA를 알려면 em.flush() 후 em.clear()를 통해 영속성 컨텍스트를 깨끗하게 비워 DB에서 값을 찾을 수 있도록 해주면 되는데 이보다 객체 지향적이면서, 1차 캐시의 영속성 컨텍스트와 실제 DB 데이터와의 데이터 차이 문제를 해결하기 위해 일대다 양쪽에 데이터를 넣어주는 게 필수적입니다. 아래 예제를 통해 확인해봅시다!

 

* 반드시 영속성 컨텍스트에 대한 내용을 숙지하고 보세요!

 

Team teamA = new Team();
team.setName("teamA");
em.persist(teamA);

Member memberA = new Member();
memberA.setName("memberA");

// memberA에 연관 관계 설정
memberA.setTeam(teamA);
em.persist(memberA);

System.out.println("memberA.getTeam : " + memberA.getTeam());
System.out.println("teamA.getMembers() : " + teamA.getMembers(0));

 

teamA에도 연관 관계 설정

teamA.getMember().add(memberA); 한 줄만 추가해주면 됩니다.

 

Team teamA = new Team();
team.setName("teamA");
em.persist(teamA);

Member memberA = new Member();
memberA.setName("memberA");

// memberA에 연관 관계 설정
memberA.setTeam(teamA);
em.persist(memberA);

// teamA에 연관 관계 설정
teamA.getMembers().add(memberA);

System.out.println("memberA.getTeam : " + memberA.getTeam());
System.out.println("teamA.getMembers() : " + teamA.getMembers(0));

 

Member Entity에 연관 관계 편의 메소드 생성

위 방법으로 해결할 수 있지만 같은 코드 반복을 방지하기 위해 Member Entity에서 연관 관계 편의 메소드를 생성합니다. 이렇게 연관 관계 편의 메소드를 사용하면 코드 중복을 방지하고 양방향 연관 관계 매핑에서 한쪽에만 연관 관계가 설정되는 것을 방지할 수 있습니다.

 

@Entity
@Getter
public Member {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "MEMBER_ID")
    private Long id;
    private String name;
    private Team team;
    
    public changeTeam(Team team) {
        
        // Member에 이미 Team이 설정되어 있을 경우
        if(this.team != null) {
         
            // team에서 해당 Entity를 제거
            this.team.getMembers().remove(this);
        }
        
        // 해당 member Entity에 파라미터로 들어온 team 연관 관계 설정
        this.team = team;
        
        // 파라미터로 들어온 team Entity에 member 연관 관계 설정
        team.getMembers().add(this);
    }
}
반응형

+ Recent posts