엔티티 매핑

 

  • 객체와 테이블 매핑: @Entity, @Table
  • 필드와 컬럼 매핑: @Column
  • 기본 키 매핑: @Id = PK
  • 연관관계 매핑: @ManyToOne, @JoinColumn

 

[Entity]

 

@Entity가 붙은 클래스는 JPA가 관리

 

  • 기본 생성자는 필수 
  • final 클래스, enum, interface, inner 클래스는 사용하면 안됨
  • 저장할 필드에는 final 필드를 사용하지 않는다.

 

 

[데이터베이스 스키마 자동 생성]

 

DDL을 애플리케이션 실행 시점에 자동 생성

테이블 중심 -> 객체 중심

 

  • 이렇게 생성된 DDL은 불안할 수 있으므로 운영서버에서는 사용 지양

 

데이터베이스 스키마 자동 생성 - 주의

운영 장비에는 절대 create, create-drop, update를 사용하면 안됨.

 

테스트 서비는 update 또는 validate!! -> 데이터 날아감..

 

스테이징 및 운영 서버는 validate 또는 none

 

 

[필드랑 컬럼 매핑]

 

@Id -> PK

@Enumerated -> db에는 enum타입이 없는데, enum 타입을 매핑할 때 사용

@Temporal -> 생성날짜, 삭제날짜 

@Lob -> varchar를 넘어서는 큰 콘텐츠 삽입

 

@Column

  • Option

 

@Enumerated

  • 기본 타입 Integer
  • String으로 타입 변경 가능
  • enum타입에서 나중에 0번째에 데이터를 추가하면 숫자와 매치되는 값이 달라서 에러가 있음, 그러므로 되도록 타입을 String으로 변경해서 사용할 .

<플러시>

 

영속성 컨텍스트의 변경내용을 데이터베이스에 반영

 

플러시가 발생

변경 감지 (더티 체킹)

수정된 엔티티 쓰기 지연 SQL 저장소에 등록

쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송

 

영속성 컨텍스트를 플러시하는 방법

 

em.fluch()

트랜잭션 커밋

JPQL 쿼리 실행

 

  • 플러시를 해도 1차 캐시는 남아있다.
  • -> 쓰기 지연 SQL 저장소에 있던거만 넘어가는 거임

 

영속성 컨텍스트를 비우지 않음

영속성 컨텍스트의 변경내용을 데이터베이스에 동기화

 

<준영속 상태>

 

영속 -> 준영속

영속 상태의 엔티티가 영속성 컨텍스트에서 분리

 

준영속 상태를 만드는 방법

 

em.detach()

em.claer();

em.close();

영속성 컨텍스트

 

JPA에서 가장 중요한 두가지

  1. ORM
  2. 영속성 컨텍스트

 

 

엔티티 매니저 팩토리와 엔티티 매니저

emf는 em을 생성하고

em은 커넥션을 사용해서 db를 사용함

 

영속성 컨텍스트:

엔티티를 영구 저장하는 환경

 

엔티티의 생명주기:

비영속, 영속, 준영속, 삭제

 

비영속: 영속성 컨텍스트와 관계가 없음

영속: 영속성 컨텍스트에 관리되는 상태

준영속: 영속성 컨텍스트에 저장되어있다가 분리된 상태

삭제: 삭제된 상태

 

  • 영속상태가 된다고 해서 바로 db에 쿼리기 가는게 아님
  • 트렌젝션을 commit 할 때 감.

 

영속성 컨텍스트

내부에 1차 캐시가 있음 

  • 1차 캐시의 이점: 조회시에 db를 조회하기 전, 1차 캐시를 먼저 조회하고 값이 있을 시, 반환이 빨라짐.
  • But 한 트렌젝션 안에서만 존재할 수 있으므로, 실제로 성능 이점을 크게 얻는다고 말할 수는 없음.

 

영속 엔티티는 동일성을 보장해준다.

(==으로 비교했을 때, true가 나옴) -> 1차 캐시로 반복 가능한 읽기 등급의 트랜잭션 격리 수준을 애플리케이션 차원에서 제공

 

persist를 하면 바로 쿼리로 쏘는게 아니라, 쓰기 지연 SQL 저장소 및 1차 캐시에 저장됨.

 

그리고 SQL 저장소에 모아둔 것은 트렌젝션 커밋을 할 때 보내짐.

 

더티 채킹: 변경감지

영속 컨텍스트가 있어서 가능.

커밋을 하면 flush()가 호출

호출 된 후 엔티티와 스냅샷을 비교

 

 

링크

https://www.acmicpc.net/problem/7569

 

7569번: 토마토

첫 줄에는 상자의 크기를 나타내는 두 정수 M,N과 쌓아올려지는 상자의 수를 나타내는 H가 주어진다. M은 상자의 가로 칸의 수, N은 상자의 세로 칸의 수를 나타낸다. 단, 2 ≤ M ≤ 100, 2 ≤ N ≤ 100,

www.acmicpc.net

 

문제

 

 

풀이

1. 토마토의 정보를 담을 배열 하나, 걸리는 시간을 담을 배열 하나해서 총 두개의 3차원 배열을 만들어준다.

2. 반복문을 통해 배열을 받아준다.

2-1. 입력을 보면, 한판을 다 받고 다음판을 받기 때문에 반복문을 배치할 때, H를 가장 밖에 둔다.

3. 배열에 있는 숫자가 1, 즉 익은 토마토일 때 시간을 나태내는 배열에 1을 넣으며, 더불어 queue에 넣고 bfs를 할 준비를 한다.

4. queue에 넣은 숫자들을 하나씩 꺼내고, 인접한 부분을 모두 탐색시킨다.

5. 3차원 배열이므로, h값 즉 zindex가 바뀌는 경우를 고려하여 추가한다.

6. 탐색을 진행하면서 안익은 토마토를 만났고, 해당 부분의 걸리는 시간이 0으로 아직 변경되지 않았을 때, 이동하기 전 토마토의 시간 + 1 값을 저장한다.

7. 탐색을 진행한 후, 다시 배열들의 탐색을 진행한다.

8. 토마토를 전부 익힐 수 있는지에 대한 여부를 판단하는 boolean 변수를 만들어 준다,.

9. 반복문을 통해 배열을 탐색하면서 토마토가 존재하는 경우(!= -1)인데 걸리는 시간이 0인 경우, 탐색이 진행되지 않은 것으로 판단하여,

설정한 boolean변수를 false로 바꾸고 break한다.

10. 그게 아니라면 계속 탐색을 진행해서 가장 큰 값을 정답으로 설정한다.

 

코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {
    static int x = 0,y = 0,z = 0;
    static int[] dz = {-1,0,0,0,0,1};
    static int[] dy = {0,1,0,-1,0,0};
    static int[] dx = {0,0,1,0,-1,0};

    static Queue<Integer[]> queue = new LinkedList<>();
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        x = Integer.parseInt(st.nextToken());
        y = Integer.parseInt(st.nextToken());
        z = Integer.parseInt(st.nextToken());

        // 입력 index
        int[][][] arr = new int[z][y][x];
        int[][][] dist = new int[z][y][x];

        for(int i = 0; i<z; i++){
            for(int j = 0; j<y; j++){
                st = new StringTokenizer(br.readLine());
                for(int k = 0; k<x; k++){
                    int num = Integer.parseInt(st.nextToken());
                    arr[i][j][k] = num;
                    if(num == 1){
                        dist[i][j][k] = 1;
                        queue.offer(new Integer[]{i,j,k});
                    }
                }
            }
        }
        int ans = 0;

        while(!queue.isEmpty()){
            Integer[] tmp = queue.poll();

            int tmpz = tmp[0];
            int tmpy = tmp[1];
            int tmpx = tmp[2];

            for(int i = 0; i<dz.length; i++){
                int nz = tmpz + dz[i];
                int ny = tmpy + dy[i];
                int nx = tmpx + dx[i];

                if(nz < 0 || ny < 0 || nx <0 || nz >= z || ny >= y || nx >= x){
                    continue;
                }
                if(arr[nz][ny][nx] == 0 && dist[nz][ny][nx] == 0){
                    dist[nz][ny][nx] = dist[tmpz][tmpy][tmpx] + 1;
                    queue.offer(new Integer[] {nz,ny,nx});
                }
            }
        }

        boolean possible = true;

        for(int i = 0; i<z; i++){
            if (!possible) {
                ans = 0;
                break;
            }
            for(int j = 0;  j<y; j++){
                for(int k = 0; k<x; k++){
                    if (!possible) {
                        ans = 0;
                        break;
                    }
                    if(arr[i][j][k] != -1&&dist[i][j][k] == 0) {
                        possible = false;
                        if (!possible) {
                            ans = 0;
                            break;
                        }
                    }
                    ans = Math.max(ans, dist[i][j][k]);
                }
            }
        }
        System.out.println(ans-1);
    }

    }

 

후기

3차원 배열 탐색할 때, 처음에 zindex를 -1로 옮기고 xy도 같이 옮겨버려서 답이 안나왔음.

처음에 bfs 메소드로 만들고 싶어서 static 선언했는데, 중간에 수업 듣느라 까먹어서 dx dy dz static 해놓은 것도 까먹음

다음번엔 메소드 단위로 짤라서 만들어보고 싶음

다음엔 주석을 좀 써볼까 고민 중

JPA를 사용할 시 @Entity

 

테이블 이름을 정해야 할 시, @Table(name = “???”)이며,

작성하지 않을 시, 관례상 클래스 이름의 소문자 테이블에 저장

 

필요시, 매핑 필요.

 

emf는 어플리케이션 로딩시점에 하나

em은 트렌젝션 단위에서 할 때마다, em을 만들어줘야함.

->ex) 고객의 요청이 올 때 마다.

 

JPA에서는 트렌젝션이라는 단위가 중요한데,

모든 데이터 변경 작업은 트렌젝션 안에서 작업해야함.

 

JPA를 통해 Entity를 가져오게 되면, JPA가 관리하면서 tx이 커밋되는 시점에 체크를 하고, 변동 사항이 있으면 업데이트 쿼리를 만듦.

-> 굳이 persist 안해도 됨

 

 

궁금한 점.

Entity는 뭐고

Entity Manager 와 Entity Manager Factory는 무엇이며…

각각 어떻게 작동하는지..?

SOLID

로버트 마틴이 좋은 객체 지향 설계의 5가지 원칙을 정리

SRP(single responsibility principle): 단일 책임 원칙

OCP(Open/Closed principle): 개방-폐쇄 원칙

LSP(Liskov substitution principle): 리스코프 치환 원칙

ISP(Interface segregation principle): 인터페이스 분리 원칙

DIP(Dependency inversion principle): 의존관계 역전 원칙

 

SRP

하나의 클래스는 하나의 책임만 가짐.

변경이 있을 때, 변경으로 인한 파급 효과가 적어야 함.

 

OCP

확장에는 열려 있으니, 변경에는 닫혀 있어야 함.

(다형성) 인터페이스를 구현한 새로운 클래스를 만들어서 새로운 기능을 구현하면,

기존의 코드를 변경하는 것은 아니다.

-> 그러나 구현 객체를 변경하는 것도 코드를 변경하는 것이다.

해결은?
객체를 생성하고, 연관관계를 맺어주는 별도의 조립, 설정자가 필요 -> 스프링 컨테이너

 

 

LSP

객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 함.

"규약을 무조건 맞춰야 함" -> 기능적 보장

다형성을 지원하기 위한 원칙

 

 

ISP

특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 나음.

클라이언트를 여러개로 분리하면 인터페이스가 명확해지고, 대체 가능성이 높아짐.

 

 

DIP

추상화에 의존해야함.

프로그램을 볼 때, 구현 클래스에 의존하는 것이 아닌 인터페이스에 의존 해야함.

인터페이스에 의존하여 바라볼 때, 유연한 구현체 변경이 가능함.

 

'Web BackEnd > TIL Memo' 카테고리의 다른 글

220318 TIL 메모, 영속성 컨텍스트  (0) 2022.03.18
220317 TIL 메모 JPA Entity  (0) 2022.03.18
이너 클래스와 이너 인터페이스  (0) 2022.01.05
인터페이스  (0) 2022.01.03
자바 제어자2  (0) 2022.01.02

이너 클래스

클래스 내부에 포함되는 이너 클래스는

인스턴스 멤버 이너 클래스, 정적 멤버 이너 클래스, 지역 이너 클래스

로 나뉜다.

 

1. 인스턴스 맴버 이너 클래스

인스턴스, 객체 내부에 맴버의 형태로 존재.

자신을 감싸고 있는 outer class의 모든 접근 지정자의 멤버에 접근할 수 있음.

 

인스턴스 멤버 이너 클래스의 객체 생성 방법

class A {

    class B {

    }

}

 

A.a = new A();

A.B b = a.new B();

 

class A_AccessMember{
    public int a = 3;
    protected int b  = 4;
    int c = 5;
    private int d = 6;
    void abc(){
        System.out.println("A 클래스 메서드 abc()");
    }

    class B_AccessMember{
        void bcd(){
            System.out.println(a);
            System.out.println(b);
            System.out.println(c);
            System.out.println(d);
            abc();
        }
    }
}

public class CreateObjectAndAccessMember {
    public static void main(String[] args) {
        A_AccessMember a = new A_AccessMember();

        A_AccessMember.B_AccessMember b = a.new B_AccessMember();
        b.bcd();
    }
}

 

아우터 클래스의 객체 참조하기

 

'아우터 클래스명.this.'를 명시적으로 붙여 사용한다.

 

'Web BackEnd > TIL Memo' 카테고리의 다른 글

220317 TIL 메모 JPA Entity  (0) 2022.03.18
좋은 객체 지향 설계의 5가지 원칙(SOLID)  (0) 2022.01.09
인터페이스  (0) 2022.01.03
자바 제어자2  (0) 2022.01.02
자바 제어자  (0) 2022.01.01

인터페이스의 정의와 특징

인터페이스는 내부의 모든 필드가 public static final로 정의되고,

static과 default메서드 이외의 모든 메서드는 public abstract로 정의된 객체지향 프로그래밍 요소다.

class키워드 대신 interface 키워드를 사용해 선언한다.

 

인터페이스 내에서는 명시하지 않고 생략하여도

public static final과 public abstract가 자동으로 추가된다.

 

인터페이스의 상속

인터페이스의 상속은 extends가 아닌 implements를 사용한다.

인터페이스의 가장 큰 특징은 다중 상속이 가능하다.

쉼표로 구분해 나열한다.

 

클래스명 implements 인터페이스명, ...., 인터페이스명{

 

}

 

*인터페이스는 모든 필드가 public static final로 정의돼 있어 충돌이 발생하지 않기 때문에, 다중 상속이 가능하다.

 

클래스가 인터페이스를 상속할 때, 인터페이스 안에는 미완성 메서드가 있다.

이 상황에서 클래스는 에러가 나는데, 클래스는 일반 클래스로 정의되어 있으므로, 내부에는 완성된 메서드만 포함되어야 하는데, 인터페이스를 상속하면서 미완성 메서드가 들어가면 오류가 뜨게 된다.

'Do it! 자바 완전 정복 408p 참조'

 

인터페이스 타입의 객체 생성 방법

인터페이스 타입의 객체 생성 방법에는 두가지가 있다.

먼저 인터페이스를 일반 클래스로 상속해 객체를 생성하는 방법이 있고,

익명 이너 클래스를 활용해 인터페이스 객체를 생성하는 방법이 있다.

 

1. 인터페이스를 일반 클래스로 상속해 객체 생성

interface A_interface{
    int a = 3;
    void abc();
}

class B_class implements A_interface{
    public void abc(){

    }
}
public class CreateObjectOfInterface_1 {
    public static void main(String[] args) {
        A_interface a1 = new B_class();
    }
}

 

2. 익명 이너 클래스

interface A_interface_2{
    int a = 3;
    void abc();
}
public class CreateObjectOfInterface_2 {
    public static void main(String[] args) {

        A_interface_2 a1 = new A_interface_2() {
            @Override
            public void abc() {

            }
        };
    }
}

 

+ Recent posts