이 글은 김영한의 [자바 ORM 표준 JPA 프로그래밍 - 기본편] 수강하며 정리한 글입니다.

 

 

🟦 기본 환경: IDE: IntelliJ, Language: Java

 

 

1차 cache

: EntityManager가 관리하는 영속성 컨텍스트(Persistence Context) 내부에 있는 첫 번째 캐시

 

비영속상태

: Entity Manager에 의해 관리되지 않는 상태

 

영속상태

: Entity Manager에 의해 관리되는 상태

 

 

⭐ 영속성 컨텍스트에 저장 ≠ DB에 저장

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
package jpa_basic;
 
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.List;
 
public class Main {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
 
        EntityManager em = emf.createEntityManager();
 
        EntityTransaction tx = em.getTransaction();
        tx.begin(); // transaction 시작 선언
 
        try {
            // 비영속: Entity Manager와 무관
            Member member = new Member();
            member.setId(100L);
            member.setName("HelloJPA");
 
            // 영속
            System.out.println("BEFORE");
            em.persist(member); // 1차 cache 저장
            System.out.println("AFTER");
 
            tx.commit(); // commit 후, DB 저장
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
 
        emf.close();
 
    }
}
 
 
 

결과

1
2
3
4
5
6
7
8
9
10
11
BEFORE
AFTER
Hibernate: 
    /* insert jpa_basic.Member
        */ insert 
        into
            Member
            (name, id) 
        values
            (?, ?)
 
 

⭐ BEFORE 출력 em.persist → AFTER 출력 → DB 저장(insert query)

 

 

1차 CACHE 조회(1)

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
package jpa_basic;
 
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.List;
 
public class Main {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
 
        EntityManager em = emf.createEntityManager();
 
        EntityTransaction tx = em.getTransaction();
        tx.begin(); // transaction 시작 선언
 
        try {
            // 비영속: Entity Manager와 무관
            Member member = new Member();
            member.setId(101L);
            member.setName("HelloJPA");
 
            // 영속
            em.persist(member); // 1차 cache 저장
 
            Member findMember = em.find(Member.class, 101L);
            // 1차 cache에 저장된 동일한 PK로 값을 조회하므로 DB에 select을 사용하지 않고도 findMember가 가능
            System.out.println("findMember.id: " + findMember.getId());
            System.out.println("findMember.name: " + findMember.getName());
 
            tx.commit(); // commit 후, DB 저장
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
 
        emf.close();
 
    }
}
 
 
 

결과

1
2
3
4
5
6
7
8
9
10
11
findMember.id: 101
findMember.name: HelloJPA
Hibernate: 
    /* insert jpa_basic.Member
        */ insert 
        into
            Member
            (name, id) 
        values
            (?, ?)
 
 

⭐ DB에 insert query 전 데이터 조회 가능

: persist ▶ persistence context의 1차 cache에 저장 ▶ find()  가장 먼저 1차 캐시 검색

: Main App 실행 시, persist()를 통해 1차 캐시에 저장된 값과 find()로 조회하고자하는 대상(매개변수 PK)이 같다면 같은 transaction 안에서 같은 영속성 컨텍스트로 관리되는 상태이므로 1차 캐시에서 조회할 수 있음

 

 

1차 CACHE 조회(2)

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
package jpa_basic;
 
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.List;
 
public class Main {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
 
        EntityManager em = emf.createEntityManager();
 
        EntityTransaction tx = em.getTransaction();
        tx.begin(); // transaction 시작 선언
 
        try {
            Member findMember = em.find(Member.class, 101L);
            Member findMember = em.find(Member.class, 101L);
 
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
 
        emf.close();
 
    }
}
 
 
 

결과

1
2
3
4
5
6
7
8
9
Hibernate: 
    select
        member0_.id as id1_0_0_,
        member0_.name as name2_0_0_ 
    from
        Member member0_ 
    where
        member0_.id=?
 
 
 

⭐ 1차 캐시가 빈 상태에서 같은 대상을 조회할 경우, select query가 1개밖에 존재하지 않음

: find() ▶ 1차 캐시 조회 ▶ DB 조회 ▶1차 캐시에 저장

: member1 - 1차 캐시에 조회할 데이터가 없으므로 DB로 select query 실행

: member2 - member1 조회한 데이터 값이 1차 캐시에 저장되었으므로 1차 캐시에서 데이터 조회(select query 발생 X)

 

 

 

참고 자료

 

JPA - 영속성(persistence란) [+1차 캐시]

영속성 Spring JPA 로고를 보면 영속성(persistence)라는 단어가 크게 그려져 있습니다. 그만큼, 영속성 없이 Spring JPA를 얘기하기 힘듭니다. 영속성은 쉽게 말하면 지속을 의미합니다. 더 자세히 풀자

jaehoney.tistory.com

 

'Java > JPA' 카테고리의 다른 글

[JPA] @PrePersist  (0) 2023.06.25
[JPA] JOIN Null값 처리  (0) 2023.06.20
[JPA_Basic] JPA persist, find, remove, update  (0) 2023.06.15
[SpringBoot_JPA_1] @PathVariable  (0) 2023.06.03
[SpringBoot_JPA_1] TypedQuery  (0) 2023.06.02

이 글은 김영한의 [자바 ORM 표준 JPA 프로그래밍 - 기본편] 수강하며 정리한 글입니다.

 

 

🟦 기본 환경: IDE: IntelliJ, Language: Java

 

 

Persistence.xml

: JPA가 접근하고자하는 DB에 대해 필요한 설정 정보들을 기술해둔 파일

→ JPA는 이 파일의 설정 정보를 바탕으로 접근할 DB의 정보를 가져 올 수 있음

 

EntityManagerFactory

: EntityManager(Entity를 관리하고 DB 관련 작업을 수행 함)를 생성

: DB 당 1개 생성

 

EntityManager

: 특정 작업을 위해 데이터베이스에 액세스 하는 역할

: DB에 저장되는 transaction 단위마다 생성

 

EntityTransaction

: 데이터베이스 트랜잭션을 관리하기 위한 인터페이스로, 트랜잭션의 시작, 커밋, 롤백 등의 작업을 수행하는 메서드를 제공

: JPA의 모든 데이터 변경은 transaction 안에서 실행

 

Transaction Structure

: commit과 rollback이 try-catch 구조를 이뤄야하며, 반드시 Entity Manager가 종료될 수 있도록 finally 사용

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 jpa_basic;
 
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.List;
 
public class Main {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        // EntityManagerFactory: Application Loading 시점에 1개만 생성(DB당 1개)
 
        EntityManager em = emf.createEntityManager();
        // EntityManager: DB에 저장되는 transaction 단위마다 생성
 
        // JPA의 모든 데이터 변경은 transaction 안에서 실행
        EntityTransaction tx = em.getTransaction();
        tx.begin(); // transaction 시작 선언
 
        try {
                // 실행하고자하는 코드
            }
 
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
 
        emf.close();
 
    }
}
 
 
 

 

JPA - 회원 가입

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
package jpa_basic;
 
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.List;
 
public class Main {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        // EntityManagerFactory: Application Loading 시점에 1개만 생성(DB당 1개)
 
        EntityManager em = emf.createEntityManager();
        // EntityManager: DB에 저장되는 transaction 단위마다 생성
 
        // JPA의 모든 데이터 변경은 transaction 안에서 실행
        EntityTransaction tx = em.getTransaction();
        tx.begin(); // transaction 시작 선언
 
        try {
                Member member = new Member();
                member.setId(2L);
                member.setName("HelloB");
                em.persist(member);
            }
 
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
 
        emf.close();
 
    }
}
 
 
 

 

JPA - 회원 조회

: 조회의 경우, commit이 필요없으므로 try-catch 구문 불필요

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
package jpa_basic;
 
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.List;
 
public class Main {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        // EntityManagerFactory: Application Loading 시점에 1개만 생성(DB당 1개)
 
        EntityManager em = emf.createEntityManager();
        // EntityManager: DB에 저장되는 transaction 단위마다 생성
 
        // JPA의 모든 데이터 변경은 transaction 안에서 실행
        EntityTransaction tx = em.getTransaction();
        tx.begin(); // transaction 시작 선언
 
        try {
                Member findMember = em.find(Member.class, 1L);
                // 1번째 parameter: Entity Class, 2번째 parameter: PK
                System.out.println("id: " + findMember.getId());
                System.out.println("name: " + findMember.getName());
            }
 
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
 
        emf.close();
 
    }
}
 
 
 

 

JPA - 회원 삭제

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
package jpa_basic;
 
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.List;
 
public class Main {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        // EntityManagerFactory: Application Loading 시점에 1개만 생성(DB당 1개)
 
        EntityManager em = emf.createEntityManager();
        // EntityManager: DB에 저장되는 transaction 단위마다 생성
 
        // JPA의 모든 데이터 변경은 transaction 안에서 실행
        EntityTransaction tx = em.getTransaction();
        tx.begin(); // transaction 시작 선언
 
        try {
                Member findMember = em.find(Member.class, 1L);
                em.remove(findMember);
            }
 
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
 
        emf.close();
 
    }
}
 
 
 

 

JPA - 회원 수정

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
package jpa_basic;
 
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.List;
 
public class Main {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        // EntityManagerFactory: Application Loading 시점에 1개만 생성(DB당 1개)
 
        EntityManager em = emf.createEntityManager();
        // EntityManager: DB에 저장되는 transaction 단위마다 생성
 
        // JPA의 모든 데이터 변경은 transaction 안에서 실행
        EntityTransaction tx = em.getTransaction();
        tx.begin(); // transaction 시작 선언
 
        try {
                Member findMember = em.find(Member.class, 1L);
                findMember.setName("HelloJPA");
 
                tx.commit(); // update를 작성하지 않아도 findMember 내용의 변경이 있을 경우, JPA 자동 update query 생성
            }
 
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
 
        emf.close();
 
    }
}
 
 
 

 

 + JPA - 전체 회원 조회

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
package jpa_basic;
 
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.List;
 
public class Main {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        // EntityManagerFactory: Application Loading 시점에 1개만 생성(DB당 1개)
 
        EntityManager em = emf.createEntityManager();
        // EntityManager: DB에 저장되는 transaction 단위마다 생성
 
        // JPA의 모든 데이터 변경은 transaction 안에서 실행
        EntityTransaction tx = em.getTransaction();
        tx.begin(); // transaction 시작 선언
 
        try {
                List<Member> result = em.createQuery("select m from Member as m", Member.class)
                        .setFirstResult(0)
                        .setMaxResults(5)
                        .getResultList();
 
                for(Member member : result) {
                    System.out.println("member.name: " + member.getName());
            }
 
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
 
        emf.close();
 
    }
}
 
 
 

createQuery

: EntityManager(em) 객체를 사용하여 쿼리를 생성하는 메서드

: JPA의 객체지향 쿼리 언어인 JPQL을 사용, Entity Class 사용

 

setFirstResult

: 조회 결과 중에서 첫 번째로 가져올 레코드의 인덱스를 설정

 

setMaxResults

: 최대로 가져올 결과 레코드 수를 설정

 

getResultList

: 쿼리를 실행하고 결과를 리스트 형태로 반환

 

 

 

참고 자료

 

JPA 작동 메커니즘

JAVA의 ORM 표준 : JPA 이전 포스팅에서 SQL 중심적인 개발의 문제점을 살펴보고 해결방법으로 JAVA의 ORM 표준인 JPA를 가볍게 언급해보았다. 그렇다면, JAVA에서는 JPA을 어떻게 지원하고 개발자들이 지

velog.io

 

'Java > JPA' 카테고리의 다른 글

[JPA] JOIN Null값 처리  (0) 2023.06.20
[SpringBoot_JPA_Basic] JPA 1차 cache  (0) 2023.06.16
[SpringBoot_JPA_1] @PathVariable  (0) 2023.06.03
[SpringBoot_JPA_1] TypedQuery  (0) 2023.06.02
[SpringBoot_JPA_1] @NoArgsConstructor  (1) 2023.05.30

이 글은 김영한의 [실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발] 수강하며 정리한 글입니다.

 

 

🟦 기본 환경: IDE: IntelliJ, Language: Java

 

 

@PathVariable

: 요청 URL에서 변수를 추출하여 메소드 매개변수에 바인딩하는 역할

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    @GetMapping("items/{itemId}/edit")
    public String updateItemForm(@PathVariable("itemId") Long itemId, Model model){
        Book item = (Book) itemService.findOne(itemId);
 
        BookForm form = new BookForm();
        form.setId(item.getId());
        form.setName(item.getName());
        form.setPrice(item.getPrice());
        form.setStockQuantity(item.getStockQuantity());
        form.setAuthor(item.getAuthor());
        form.setIsbn(item.getIsbn());
 
        model.addAttribute("form", form);
        return "items/updateItemForm";
    }
 
 
 

: Long itemId 메소드 매개변수에 itemId의 값이 URL 경로에서 추출되어 매핑

→ itemId의 값을 사용하여 itemService에서 해당하는 Book 아이템을 조회

 

'Java > JPA' 카테고리의 다른 글

[SpringBoot_JPA_Basic] JPA 1차 cache  (0) 2023.06.16
[JPA_Basic] JPA persist, find, remove, update  (0) 2023.06.15
[SpringBoot_JPA_1] TypedQuery  (0) 2023.06.02
[SpringBoot_JPA_1] @NoArgsConstructor  (1) 2023.05.30
[SpringBoot_JPA_1] @Transactional  (0) 2023.05.29

이 글은 김영한의 [실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발] 수강하며 정리한 글입니다.

 

 

🟦 기본 환경: IDE: IntelliJ, Language: Java

 

 

TypedQuery

: 작성한 JPQL을 실행시키기 위해 만드는 쿼리 객체

 * 반환 Type이 확실할 경우 TypedQuery, 불확실할 경우 Query 사용

 

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
    public List<Order> findAllByString(OrderSearch orderSearch) {
 
        String jpql = "select o from Order o join o.member m";
        boolean isFirstCondition = true;
 
        // 주문 상태 검색
        if (orderSearch.getOrderStatus() != null) {
            if (isFirstCondition) { // status 추가
                jpql += " where";
                isFirstCondition = false;
            } else {
                jpql += " and";
            }
            jpql += " o.status = :status";
        }
 
        TypedQuery<Order> query = em.createQuery(jpql, Order.class)
                .setMaxResults(1000);
 
        if (orderSearch.getOrderStatus() != null) {
            query = query.setParameter("status", orderSearch.getOrderStatus());
        }
 
        return query.getResultList();
    }
 
 
 

1. createQuery()

: 쿼리 생성

 - createQuery(jpql, returnType)

🚨 조회 column이 2개 이상일 경우, 배열로 반환되지만 TypedQuery<Order[]>로 선언하지 않음

→ 쿼리 결과가 Order[]로 지정되는 것이 아니라 개별 Order 엔티티 객체들의 컬렉션 또는 결과 목록으로 반환되기 때문에 TypedQuery<Order>를 유지

 

2. setMaxResults()

: 조회 결과 수 제한

 

3. setParameter()

: 위치 또는 이름기준 파라미터 바인딩

 - setParameter(바인딩 될 변수, 바인딩 될 값)

cf. 이름 기준 바인딩

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
    public List<Order> findAllByString(OrderSearch orderSearch) {
 
        String jpql = "select o from Order o join o.member m";
        boolean isFirstCondition = true;
 
        // 주문 상태 검색
        if (orderSearch.getOrderStatus() != null) {
            if (isFirstCondition) { // status 추가
                jpql += " where";
                isFirstCondition = false;
            } else {
                jpql += " and";
            }
            jpql += " o.status = ?1";
        }
 
        TypedQuery<Order> query = em.createQuery(jpql, Order.class)
                .setMaxResults(1000);
 
        if (orderSearch.getOrderStatus() != null) {
            query = query.setParameter(1, orderSearch.getOrderStatus());
        }
 
        return query.getResultList();
    }
 
 
 

: status → ?1

"status" → 1

 

4. getResultList()

: 결과를 컬렉션(데이터 집합)으로 반환, 없을 경우 빈 컬렉션을 반환하며 1건이라도 1건이 저장된 컬렉션 반환

cf. getSingleResult()

: 결과가 1건일 때 사용하며, 없을 경우-NoResultException, 2건 이상일 경우-NonUniqueResultException 발생

 

 

 

참고 자료

 

[jpa] JPQL

JPA에서 현재까지 사용했던 검색은 아래와 같다. 식별자로 조회 EntityManager.find() 객체 그래프 탐색 e.g. a.getB().getC() 하지만 현실적으로 이 기능만으로 어플리케이션을 개발하기에는 무리이다. 그

joont92.github.io

 

이 글은 김영한의 [실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발] 수강하며 정리한 글입니다.

 

 

🟦 기본 환경: IDE: IntelliJ, Language: Java

 

 

@NoArgsConstructor

: 파라미터가 없는 기본 생성자 생성

 

OPTION

 - AccessLevel.PROTECTED

: 기본 생성자의 접근 제어 = PROTECTED

: 같은 pkg 또는 자식 class를 제외한 외부 클래스에서는 해당 객체의 인스턴스를 생성할 수 없음

 - (default) AccessLevel.PUBLIC

: 기본 생성자의 접근 제어 = PUBLIC

: 모든 위치에서 접근 가능

 

@Entity를 통해서 기본생성자를 만들 수 있지만 @NoArgsConstructor를 통한 접근 제한을 지정함으로써 무분별한 기본 생성자의 생성을 막을 수 있음

= 모든 필드에 대한 값이 반드시 제공되어야만 클래스의 인스턴스를 생성할 수 있도록 제어

1
2
3
4
5
6
7
8
9
10
11
public class ExampleClass {
    private String field1;
    private int field2;
 
    @NoArgsConstructor(AccessLevel.PROTECTED)
    public ExampleClass(String field1, int field2) {
        this.field1 = field1;
        this.field2 = field2;
    }
}
 
 
cs

ExampleClass에 대한 @NoArgsConstructor를 선언함으로써 불완전한 객체 생성을 방지

1
2
3
ExampleClass example = new ExampleClass();
// 기본 생성자가 없으므로 Error 발생
 
 
cs

 

⭐ 요약

 * Class + @NoArgsConstructor: 기본 생성자 생성

 * Constructor + @NoArgsConstructot: 해당 생성자 이외의 생성자는 생성되지 않음

 

 

cf. @Entity 선언 시, 생성자가 필요한 이유

: JPA에서 Entity Proxy를 만들기 위해서는 반드시 기본 생성자 하나를 생성해야 함

: Entity Proxy는 JPA의 지연 로딩(lazy loading) 기능을 구현하는 데 사용

1. 엔티티 클래스를 상속받아 프록시 클래스 생성
2. JPA는 리플렉션을 사용하여 프록시 객체를 생성
3. 프록시 객체는 엔티티의 실제 데이터를 지연해서 로딩

 

* JPA Reflection: 엔티티 클래스의 메타데이터를 조사하여 객체와 데이터베이스 간의 매핑을 구성

 

 

 

참고 자료

 

자주 사용되는 lombok, 주의 사항 | devk0ng's blog

@Getter, @Setter : 말그대로 getter, setter method를 생성해주는 놈이야! AccessLevel을 명시해줌으로써 접근제한자를 지정 해 줄 수 있어. 123456789public Class Sample { @Getter private String attr1; @Getter(AccessLevel.PRIVATE)

devk0ng.github.io

 

@NoargsConstructor(AccessLevel.PROTECTED) 와 @Builder

@NoargsConstructor(AccessLevel.PROTECTED) 와 @Builder를 함께 사용할때 주의할 점에 대해서 서술합니다. "왜" 안되는지와 "왜" 이렇게 해결 할 수 있는지에 대해 집중하여 서술합니다. 1. 왜 NoargsConstructor(Access

cobbybb.tistory.com

 

'Java > JPA' 카테고리의 다른 글

[SpringBoot_JPA_1] @PathVariable  (0) 2023.06.03
[SpringBoot_JPA_1] TypedQuery  (0) 2023.06.02
[SpringBoot_JPA_1] @Transactional  (0) 2023.05.29
[SpringBoot_JPA_1] Dirty Checking & Merge  (1) 2023.05.28
[SpringBoot_JPA_1] StringUtils.hasText()  (0) 2023.05.27