반응형

 

BinarySearch를 사용하면 검색 범위를 logN으로 엄청나게 단축시킬 수 있다.

만약 탐색할 범위가 너무 크다면 고려해봐야 한다.

 

특히 응용이라고 할 수 있는 최댓값, 최솟값을 찾아야 하는 이분 탐색을 이용하는

매개 변수 탐색 Parametric Search는 굉장히 유용하다.

 

주의할 점은 이분 탐색을 사용하기 이전에 탐색할 배열은 무조건 정렬되어있어야 한다.

이분 탐색은 기준 값가변 값을 통해 Start와 End를 결정한다.

 


 

 

package Search.BinarySearch;

public class BinarySearchTest {

    static int[] arr;

    public static void main(String[] args) {
        arr = new int[]{1,3,5,7,9,11,13};
        int idx = BinarySearchCode(9);
        System.out.println(idx);
    }

    public static int BinarySearchCode(int findNumber){
        int s = 0;
        int e = arr.length - 1;
        int mid;

        int returnNumber = 0;

        while(s <= e){
            mid = (s+e) / 2;

            if(findNumber == arr[mid]) {
                returnNumber = mid;
                break;
            }
            else if(findNumber > arr[mid])
                s = mid + 1;
            else if(findNumber < arr[mid])
                e = mid - 1;
        }
        return returnNumber;
    }
}

 

이분 탐색의 코드 자체는 간단하다.

left에서 시작하는 s, right에서 시작하는 e가 서로 교차하게 되면 종료한다.

 

(s+e)/2를 이용한 중간 값 mid를 계속 조건에 맞게 변화시키며 탐색범위를 이분한다.

찾지 못하였다면 그냥 종료될 것이고, 찾았다면 idx를 리턴한다.

 

 


 

 

이분 탐색에서 가장 중요하다고 생각하는 점은

변하는 가변 값과 변하지 않는 기준 값이다.

 

기준 값과 가변 값과의 비교를 통해 s, e 범위를 결정한다.

 

현재 코드에서는 찾을 숫자(기준 값)를 기준으로

mid를 이용해서 가변 값과의 비교를 통해 s, e를 결정하고 있지만

Prametric Search를 하게 되면 기준 값은 문제를 보고 결정을 해주어야 한다.

 

 


 

public static long binarySearch(int need){
    long s = 0;
    long e = 2_000_000_000;
    long returnHeight = 0;

    while(s <= e){
        long mid = (s + e) / 2;

        // 기준값 설정
        // 자른 값들의 총합을 이용
        long sum = 0;
        for(int i = 0; i<arr.length; i++){
            int ele = arr[i];
            if(ele > mid)
                sum += ele - mid;
        }

        if(sum >= need) { // 조건을 만족하므로 범위를 더 엄밀하게 줄임
            s = mid + 1;
            returnHeight = mid;    // 조건을 충족한다면 일단 저장
        }else if(sum < need)
            e = mid - 1;
    }
    return returnHeight;
}

 

백준 2805 나무자르기 문제의 코드 일부다.

 

해당 문제에서 기준 값은 need 이다. (함수의 매개변수로 받고 있음)

가변 값은 mid를 이용해 구한 sum이다.

 

mid를 기준으로 자른 값들의 총합(sum)이 need 이상이면,

더 엄밀하게 자르기 위해 s를 더 올려서 mid를 높인다.

만족하지 않는다면 e를 낮춰서 mid를 낮춘다.

 

탐색 범위를 마지막에 만족하는 것까지 좁힐 수 있으므로 최대값을 구할 수 있다.

 

 

 

이분 탐색, 매개 변수 탐색을 구현할 땐 기준 값, 가변 값을 무엇으로 할 지 항상 생각하자.

 

 


Prametric Search 문제

 

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

 

2805번: 나무 자르기

첫째 줄에 나무의 수 N과 상근이가 집으로 가져가려고 하는 나무의 길이 M이 주어진다. (1 ≤ N ≤ 1,000,000, 1 ≤ M ≤ 2,000,000,000) 둘째 줄에는 나무의 높이가 주어진다. 나무의 높이의 합은 항상 M보

www.acmicpc.net

 


 

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

 

1654번: 랜선 자르기

첫째 줄에는 오영식이 이미 가지고 있는 랜선의 개수 K, 그리고 필요한 랜선의 개수 N이 입력된다. K는 1이상 10,000이하의 정수이고, N은 1이상 1,000,000이하의 정수이다. 그리고 항상 K ≦ N 이다. 그

www.acmicpc.net

 

반응형
반응형

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

 

1699번: 제곱수의 합

어떤 자연수 N은 그보다 작거나 같은 제곱수들의 합으로 나타낼 수 있다. 예를 들어 11=32+12+12(3개 항)이다. 이런 표현방법은 여러 가지가 될 수 있는데, 11의 경우 11=22+22+12+12+12(5개 항)도 가능하다

www.acmicpc.net

 


 

다이내믹 프로그래밍을 이용한 문제다.

1, 4, 9, 16.. 과 같은 제곱수를 활용하여 주어진 수 N을 최소한의 개수로 구성하는 것이 답이다.

 

최적의 값을 idx에 기억해두는 바텀업 방식으로 이중 for문을 사용했다.

해당 문제에서 최적의 값은 최소한의 연산 횟수다.

 


 

DP 테이블 초기화

먼저 dp 테이블을 idx는 숫자, value는 최소 연산 횟수로 사용된다.

각 제곱수 idx 는 1로 만들어 주고,

나머지는 min을 알아내야 하니 충분히 큰 값으로 채워놓는다.

 


 

첫 for문은 1부터 100_000까지 차례대로 최소 연산을 구하게 된다.

 

두번째 for문은 최소 연산을 구하기 위해 

j의 제곱이 i 기준 수 보다 크면 의미가 없으므로 continue 하고,

 

j의 제곱이 i 기준 수보다 작다면 몫과 나머지를 구해서 

나머지 값에 해당되는 idx에 해당되는 값 + 현재 몫으로 이전에 구해둔 값과 비교해서 최적의 값을 구할 수 있다.

 

바텀업 방식이니

나머지값에 해당되는 idx는 현재 i 위치보다 이전 값일 것이고, 

최적의 값이라는 것이 보장되고 사용하기 무리가 없다.

 

예전에 풀었던 1463번 1로 만들기 문제와 비슷하다.


코드

 

 

import java.io.*;
import java.math.BigInteger; // subtract , multiply, add, mod
import java.util.*;

public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
    static StringTokenizer st;
    static StringBuilder sb = new StringBuilder();

    public static void main(String[] args) throws IOException {
        int number = Integer.parseInt(br.readLine());

        // dp 초기화
        int[] dp = new int[100001];
        Arrays.fill(dp, 1000_000);
        dp[0] = 0;
        for(int i = 1 ; i * i<dp.length; i++){
            int powNumber = i * i;
            dp[powNumber] = 1;
        }

        // 1부터 100_000 까지 min을 채워나가기
        for(int i = 1 ; i<dp.length; i++){
            for(int j = 325; j >= 1; j--){
                int jNumber = (int)Math.pow(j, 2);

                if(jNumber > i) // 기준숫자보다 제곱이 커지면 의미가 없으니 넘김
                    continue;

                int divide = i / jNumber;
                int rest = i % jNumber;

                dp[i] = Math.min(dp[i], dp[rest] + divide);
            }
        }
        System.out.println(dp[number]);
    }
}

 

 

반응형
반응형

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

 

2206번: 벽 부수고 이동하기

N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 당신은 (1, 1)에서 (N, M)의 위치까지 이동하려 하는데, 이때 최단 경로

www.acmicpc.net

 

 


 

처음 시도 때 시간 초과로 풀지 못한 문제다.

 

모든 벽을 큐에 넣고 해당 부분을 0으로 만들었다가 bfs가 종료되면 다시 1로 만드는 식으로

과정을 진행시켰는데 시간초과가 걸렸다.

 

 

생각을 해보면 BFS는 최단 경로를 찾을 수 있고,

Node class를 만들어서 BFS를 하면 해당 Node가 가장 먼저 도착한 Node일 테니 

벽을 뚫은적이 있는지, 없는지에 대한 상태를 저장시키면서 진행하면 될 것 같았다.

 

 

3차원 배열을 이용한 풀이가 있는데, 

3차원을 쓰지 않고, 방문처리 배열을 따로 사용하지 않고도

단순 2차원 graph로 로직 처리를 해주면 풀 수 있다.

 

 

  2
벽을 뚫은 적 x O O O X
벽을 뚫은 적 o O X X X

 

 

BFS 큐에 넣기 전 해당 위치의 값을 확인해서 사용가능성을 판단해주면 된다.

 

 

0

[ 방문하지 않은 상태 ]

 두 상태 다 사용 가능

해당 위치를 재방문 방지를 위해 2로 바꾼다.

 

 

1

[ 벽 ]

방문한 Node가 이미 벽을 뚫었다면 더 뚫을 수 없으므로 continue (더이상 뚫을 수 없음)

방문한 Node가 벽을 안뚫었다면 상태를 벽을 뚫은 상태로 바꾼다. 해당 위치는 다시 사용할 일이 없으므로 값을 3으로 바꾼다.

 

 

2

[ 벽을 뚫은 적 없는 Node를 위해 중간 방문 처리함 ]

방문한 Node가 벽을 뚫은 상태라면  continue (앞서 간 Node가 있음)

방문한 Node가 벽을 뚫지 않은 상태라면 해당 위치를 다신 사용하지 않도록 3으로 바꾼다.

 

 

3

[ 완전 방문된 상태 ]

해당 위치는 모든 노드가 사용할 수 없다.

(벽을 뚫지 않은 Node가 이미 지나간 상태)

 

 

 

 

벽을 뚫은 적이 없는 Node가 해당 위치를 완전 방문 처리하는 우선권이 있다고 생각하고, 최종 결정권을 준다.

방문한 Node의 상태를 확인하여 위치를 4가지 분기로 나눠서 해결해줄 수 있다.

 

 


 

import java.io.*;
import java.util.*;

public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
    static StringTokenizer st;
    static StringBuilder sb = new StringBuilder();

    static int[][] graph;

    static Queue<Node> q = new LinkedList<>();
    static int low, col;
    static int[] xRange = {1, -1, 0, 0};
    static int[] yRange = {0, 0, 1, -1};

    public static void main(String[] args) throws IOException {
        StringTokenizer st = new StringTokenizer(br.readLine());

        low = Integer.parseInt(st.nextToken());
        col = Integer.parseInt(st.nextToken());

        graph = new int[low][col];

        for(int i = 0; i< graph.length; i++){
            String str = br.readLine();
            int idx = 0;
            for(int j =0; j< graph[i].length; j++){
                int ele = Integer.parseInt(str.charAt(idx) +"");
                graph[i][j] = ele;
                idx++;
            }
        }
        System.out.println(bfs());
    }

    //
    public static int bfs(){
        int dis = 1;
        q.add(new Node(0, 0, false, dis));
        graph[0][0] = 2;

        int[] xRange = {1, -1, 0, 0};
        int[] yRange = {0, 0, 1, -1};

        while(!q.isEmpty()){
            Node node = q.poll();
            dis = node.dis;
            if(node.x == graph.length - 1 && node.y == graph[0].length -1)
                return dis;

            for(int i = 0; i<4; i++){
                int x = xRange[i] + node.x;
                int y = yRange[i] + node.y;
                if(x>=0 && x<low && y>=0 && y<col){
                    int disn = node.dis + 1;

                    if(graph[x][y] == 3)
                        continue;

                    if(node.state){
                        if(graph[x][y] == 0) {
                            q.offer(new Node(x, y, node.state, disn));
                            graph[x][y] = 2;
                        }

                    }else{
                        if(graph[x][y] == 0 || graph[x][y] == 2){
                            q.offer(new Node(x, y, false, disn));
                            graph[x][y] = 3;
                        }

                        else if(graph[x][y] == 1){ // 벽을 뚫는다.
                            q.offer(new Node(x, y, true, disn));
                            graph[x][y] = 3;
                        }
                    }
                }
            }
        }
        return -1;
    }
}

class Node{
    int x;
    int y;
    boolean state;
    int dis;
    Node(int x, int y, boolean state, int dis){
        this.x = x;
        this.y = y;
        this.state = state;
        this.dis = dis;
    }
}
반응형
반응형

파일 시스템 오류 (-2147416359) 해결하기


 

해당 오류는 microsoft의 모든 앱이 작동되지 않습니다.

저는 sticky notes에 중요한 메모를 적어놨는데

microsoft의 모든 앱들이 켜지지가 않았습니다.



해결 방법을 알려드리겠습니다.


 

 

해결방법

 

 

 

windows + R을 눌러서 services.msc 라고 입력합니다.

 

 


 

 

 

서비스중 windows 라이선스 관리자 또는 windws license manager 를 찾습니다.

 

 


 

 

 

 

해당 서비스를 더블클릭하고 시작유형을 "자동"으로 수정합니다.

 

 

그후 재부팅하시면 microsoft 앱들이 정상 동작합니다. !!

반응형
반응형

빌드 도구 gradle 사용

 

공통사항

 

application.properties - DB연결

spring.datasource.url=jdbc:mysql://localhost:3307/스키마명?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul
spring.datasource.username=유저명
spring.datasource.password=유저비밀번호

 

build.gradle - mysql 종속성 추가

dependencies {
    implementation 'mysql:mysql-connector-java:8.0.29'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-web'

 


 

JPA 연동

 

build.gradle

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

 


 

myBatis 연동

 

build.gradle

implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.2'

 

application.properties - mapper 패키지 추가 // db snake_case와 java camelCase 매핑 

mybatis.type-aliases-package = com.example.project.mapper
mybatis.configuration.map-underscore-to-camel-case=true

 

반응형
반응형

[학습일지] Java & SpringBoot로 시작하는 웹 프로그래밍 : 자바 인강 8주차


 

8주차 학습 내용

REST API

HTTP PROTOCOL

SPRING BOOT

 

 


REST API

 

REST: 자원의 상태 전달

1. URI를 이용해서 자원을 식별해야함
2. 데이터를 전달할 수 있다 주로 json, html
3. http 프로토콜을 통해 데이터의 처리방식을 포함 - GET, POST, PUT, DELETE

4. 응답 데이터뿐만 아니라 추가적인 URI 정보를 제공할 수 있다.

 



URI - 자원을 나타내는 주소 값
URL - 자원의 위치를 식별하는 주소

 


 

설계규칙
계층관계는 / 를 사용한다.
하이픈은 가독성을 높이는데 이용한다.
소문자를 사용한다

복수형을 사용한다.
파일확장자를 명시하지 않는다.
세션을 명시하지 않는다.

 


HTTP PROTOCOL

 

컴퓨터에서 다루는 대부분의 데이터는 전송할 수 있다.

클라이언트가 서버에게 request , 서버의 response를 클라이언트가 받는 방식으로 작동한다.

 

HTTP METHOD
get - 자원 취득
post - 자원 생성, 수정
put - 자원 수정
delete - 자원 삭제

 


응답상태코드
1.. 처리중

2.. 성공

3.. 리다이렉트

4.. 클라이언트 에러

5.. 서버 에러

 


SPRING BOOT


 SPRING BOOT의 가장 큰 장점은 사전 구성이 거의 필요 없다.
기존에 사전 구성을 하기 위해 xml 설정이 과도하게 필요했는데 현재는 xml 요구사항이 전혀 없다.
또한 WAS를 내장하고 있기 때문에 별도의 설치가 필요 없다.

 

REST API를 활용하여 Get method를 이용하여 URI 정보를 받는 여러가지 방식


RequstMapping에 주소를 명시한다.
GetMapping에 세부 주소를 명시한다.

 

요청 정보 받기
PathVariable 은 주소에 { } 를 사용한다.
RequestParam 은 ?name=값 처럼 이용한다.
또한 DTO를 사용할 수도 있다.

 


 

REST API를 활용하여 Post method를 이용하여 정보를 받는 여러가지 방식

RequestBody 데이터를 HTTP body에 넣어서 전송
      DTO 를 body 에 전송할 땐 해당 어노테이션 사용

객체는 카멜케이스, json은 스네이크케이스이므로
칼럼에 JsonProperty
객체에 JosnNaming
body에 전달되어 오는 json을 객체에 매핑
객체를 json으로 변환시키고 return 시킬 수 있음

 



Put
PathVariable 수정할 자원을 명시

전달받기 위해 RequestBody를 활용할 수 있다.

 



Delete
PathVariable 삭제할 자원을 명시

역시 전달받기 위해 RequestBody를 활용할 수 있다.


json -> object 할때는 objectMapper사용하면 편리하다.

 


 

반응형
반응형

JPA 관계 설정

자바 관점에서 생각하지 말고, RDB 관점에서도 생각해야한다.

 

JPA에서는 연관 관계의 주인이라는 개념이 있다.

연관 관계의 주인이란 외래 키를 관리하는 주체이다.

 

 

관점의 불일치

(1)

RDB에서는 한 곳에서 외래키를 갖고 있는데 자바에서는 양방향 매핑시 양쪽 모두 서로의 Entity를 갖고 있음

RDB에서는 해당 필드(칼럼)이 없는데 자바에는 존재

관점이 다르기 때문에 발생하는 문제로 RDB 외래키를 관리해주는 Entity를 누구로 할지 결정해야한다.

 

(2)

자바는 단방향 매핑이면 참조타입이 없는 한쪽에서 다른쪽으로 접근하는 것이 불가능,

RDB는 외래키를 이용해서 조인하면 서로 접근이 가능

 

 

 

Q&A

무조건 외래 키가 있는 쪽이 연관 관계의 주인 ?

 - 대부분의 경우엔 그렇다. 하지만 외래키가 없는 Entity가 관계의 주인이 될 수 있다.

 

외래키가 없는 곳을 굳이 연관 관계의 주인으로 지정하는 이유?

 - 편하다. 외래 키가 없음에도 연관 관계 CRUD가 완벽 동작

 

원래 외래키가 있는 곳에서의 CRUD는?

 - 양방향 매핑이라면 전부 정상 동작한다. 외래 키가 없는 곳에서 CRUD를 하기 위함이다.

 

단점은 없는지?

 - 외래 키 설정을 위한 추가 update 쿼리가 동작한다. (성능 저하)

 

mappedBy로 외래 키가 있는 반대편을 지정하는 이유?

 - 코드 가독성 측면에서 수많은 Entity를 볼 때 양방향 매핑이 돼있음을 알림,

   JPA에게 반대편 Entity가 주인임을 알림(매핑 테이블 생성과 검색을 방지),

   외래 키가 있는 곳에서만 외래 키를 관리하여 복잡도를 줄이기 위함

 

 


 

✔ 단방향 관계

한쪽만 매핑 어노테이션을 설정한 것

@ManyToOne, OneToMany 알맞게 설정하고

@JoinColumn으로 외래키를 갖고 있는 쪽을 가르킨다.

 

 

(1) 다대일 

RDB와 JAVA 관점을 일치시키는 방식.

RDB 외래 키가 있는 곳을 연관 관계의 주인으로 설정

 

(2) 일대다 

RBD와 JAVA 관점이 불일치되는 방식.

외래 키가 없는 곳에만 매핑 어노테이션 설정

외래키가 있는 Entity에는 매핑 어노테이션을 설정하지 않는다. 단순히 long boardId

RDB 외래키가 없는 곳을 연관 관계의 주인으로 설정

 

다쪽에 있는 외래 키를 수정하기 위해 추가적인 update쿼리가 동작한다.

이 방식보다는 차라리 양방향 매핑을 사용하므로, 많이 사용하는 방식은 아니다.

 

 

 

* 양방향에서의 관계 주인 (CRUD의 가능 여부)

✔ 양방향 관계

양쪽이 매핑 어노테이션을 설정한 것

모든 테이블을 양방향 관계로 설정하면 복잡성이 증가하므로 필요할 때만 양방향 관계 지정

 

사실 단방향 만으로도 Entity 간의 관계 설정은 완료된 것이다.

(RDB는 한쪽만 외래키를 갖는 식으로 완벽히 동작해왔다.)

 

 

 

✔ 외래 키가 없는 Entity에서 반대쪽 Entity의 외래 키를 인식하게 하는 방법은 두 가지

(1) mappedBy 

외래 키는 반대쪽 Entity가 갖고 있음을 알려준다.

 

mappedBy가 없으면?

RDB에서 외래 키가 없는 테이블에 외래 키를 생성하게 된다. (조회 필드를 외래 키로 잘못 인식해버린다.)

JPA가 양방향인 것을 모르고 해당 필드가 외래키로 인식되어 매핑 테이블을 생성하고, 그곳에서 관계 정보를 찾으려고 한다.

JPA가 만든 양쪽 Entity id를 갖는 매핑 테이블에는 당연히 아무런 정보가 들어가 있지 않아 찾지 못한다.

 

 

 

(2) JoinColumn 

반대쪽 Entity를 가리키면 연관 관계의 주인을 외래 키가 없는 곳으로 설정

이 방식을 권장하지 않는 이유는 추가적인 쿼리를 소모하게 된다.

두 Entity의 데이터를 새로 추가시킨다고 했을 때 외래키가 없는 Entity로 save()하면

 

Entity1 insert ---> Entity2 insert ---> 외래키가 있는 Entity를 update

 

insert 만으로 끝날 동작을, 반대편 Entity 외래 키를 update 하며 추가적인 쿼리가 소모된다.

성능을 희생하고, 편의를 증가

두 Entity 모두 CRUD가 가능해진다.

 


 

양방향 매핑 두 가지 방법

 

(1) JoinColumn(외래 키가 있는 곳에 설정), mappedBy(외래키가 없는 곳에 설정)

       -> mappedBy가 있는 Entity는 외래키를 관리하지 않는다.

 

연관 관계의 주인을 외래키가 있는 곳으로 설정, 권장되는 방식

외래키가 존재하는 Entity에서 연관 Create, Select, Update, Delete가 가능

mappedBy 쪽에서도 cascade 설정하면 Insert 빼고는 다 전이된다.

 

@Entity
public class Troop {
    @OneToMany(mappedBy="troop")
    public Set<Soldier> getSoldiers() {
    ...
}

@Entity
public class Soldier {
    @ManyToOne
    @JoinColumn(name="troop_fk")
    public Troop getTroop() {
    ...
}         

 

 

 

 

(2) JoinColumn(외래 키가 없는 곳에 설정)

 

연관 관계의 주인을 외래키가 없는 곳으로 설정, 편의를 위해 성능을 희생시키는 방식

양쪽 모두 Create, Select, Update, Delete가 가능 (복잡도 증가)

 

@Entity
public class Troop {
    @OneToMany
    @JoinColumn(name="troop_fk") //we need to duplicate the physical information
    public Set<Soldier> getSoldiers() {
    ...
}

@Entity
public class Soldier {
    @ManyToOne
    @JoinColumn(name="troop_fk", insertable=false, updatable=false)
    public Troop getTroop() {
    ...
}

 

양방향 매핑 시에는 순환 참조, 순환 삭제 등 신경 써줘야 할 사항들이 생겨 복잡도가 증가한다.

그래서 mappedBy로 조회만 하고, 나머지는 연관 관계의 주인으로 처리하는 방식이 권장된다.

 

https://docs.jboss.org/hibernate/stable/annotations/reference/en/html/entity.html#entity-mapping-association

 

Chapter 2. Mapping Entities

In Section 2.4.5.1, “Lazy options and fetching modes” we have seen how to affect the fetching strategy for associated objects using the @Fetch annotation. An alternative approach is a so called fetch profile. A fetch profile is a named configuration a

docs.jboss.org

 

 


Cascade

연관관계 Entity에 대한 영속성 전이 설정

dafault는 아무것도 설정되어있지 않다.

 

persist - 연관 Entity를 영속성 콘텍스트에 manage 되게 전이시킨다.

merge - 연관 Entity를 update 할 수 있게 한다.

detach - 연관 Entity를 영속성 콘텍스트에서 관리하지 않는다.

remove - 연관 Entity를 함께 제거한다.

 

 

 

orphanRemoval

연관 Entity만 삭제하고 싶을 때 사용한다.

 

set...(null)을 할 경우 외래키가 없는 것으로 update 된다.

이때 자동으로 연관 설정이 없는 Entity를 DB에서 제거하고자 할 때 사용한다. 

(cascade는 set..(null)로 동작하지 않는다.)

 

 


Entity를 영속성 컨텍스트에서 사용할 때 연관 Entity 설정 (fetch type)

 

LAZY

가장 먼저 lazy를 사용하기 위해선 Entity가 영속성 컨테이너에 관리되어지고 있어야 한다.

연관 관계 Entity가 필요할 때만 get()으로 연관 Entity를 select를 통해 나중에 가져온다.

 

EAGER

연관 관계 Entity를 영속성 컨테이너로 전부 즉시 가져온다.

 

LAZY가 보편적 권장 사항

 

 

 

 

✔ N+1 

1대 N 관계에서 1인 Entity를 findAll()했을 경우 Many Entity와 조인해서 한번에 가져올 것을 기대한다.

 

하지만, 실제 동작은 1인 Entity를 먼저 select 한 후, 1인 Entity의 id를 이용해서

매번 from N where Entity_id = id(1인 Entity의 id값)로 N 테이블에서 여러 번의 select로 id값을 확인한다.

 

[1회] select로 id 개수 확인 ---> [N회] id 개수만큼 select 동작

 

 

여러 번의 select보다 조인을 사용하고 싶을 때

1.  jpql - join fetch 이용

(join과의 차이: 연관 Entity도 한번에 가져온다)

2.  @EntityGraph에서 join 할 Entity 지정

(중복 데이터가 있을 수 있다. distinct사용)

 

 

 

 

✔ sql select의 실행 횟수 vs 조인된 데이터의 양 

두 가지를 고려하여 어떤 것이 더 효율적인가를 고려해야 한다.

 

sql select의 실행 횟수가 너무 많다면, DB를 반복적으로 접근해서 IO가 발생, 느려진다. -> 조인을 하는 선택을 한다.

가져온 데이터의 양이 너무 과하면 -> sql select를 필요한 것만 수행, 연관 Entity 정보만 가져오는 것을 선택한다.

 


참고

 

https://catsbi.oopy.io/f3204fd9-954c-44d7-ab18-2ca56000c5e5

 

다양한 연관관계 매핑

연관관계 매핑시 고려사항 3가지

catsbi.oopy.io

 

반응형
반응형

WAS

톰캣이다.

톰캣은 Java servlet을 관리한다.

 

톰캣외에도 WAS가 있지만 톰캣을 가장 많이 사용

 

 

역할

통신지원

멀티 스레드 관리

서블릿 생명주기 관리

세션 관리

 

동작방식

Request, Response 객체 생성 -> servlet에게 전달 /스프링/ spring dispatcher servlet 

 

 

 

용어 정리

 

✔ Socket

IP + Port

HTTP도 Socket을 사용함, Web Socket 통신이 아닐뿐임

 

✔ HTTP 통신

요청에 대한 응답을 주고 바로 통신을 해제

TCP 위에서 보편적으로 사용, UDP 위에서도 사용가능함 (Youtube QUIC)

 

✔ Web Socket 통신

HTTP와 달리 통신을 유지하며 실시간 통신 지원

처음 요청시 HTTP Get 으로 Upgrade:web socket 헤더를 추가하여 보냄

 

 

 

 Web Server

HTTP, HTTPS 통신을 위해 Server는 (IP + 80번, 443번)으로 socket 생성

정적인 데이터를 응답

 

✔ Web Container == Servlet Container

웹 컨테이너는  자바 서블릿과 상호작용한다.

동적인 처리를 위한 Servlet들이 모인 Container, JAVA에서는 동적 처리로 Servlet을 이용한다.

클라이언트의 URL에 맞는 Servlet을 매핑

(스프링에서는 Dispatcher Servlet 하나의 Servlet으로 URL에 맞는 Controller를 Handler Mapping)

 

  • 서블릿 객체의 생명주기 담당
  • 싱글톤 패턴으로 관리
  • 멀티 스레딩 지원

 

 

✔ Web Container Server == Web Application Server(WAS)

Web Container + Web Server

요청에 대한 동적인 데이터를 처리하여 응답

WAS에도 Web Server가 존재하지만 보안, 로드밸런싱, 정적데이터 처리를 위해 Web Server를 앞단에 하나 더 둠

 

 

 

 

 


JSP 라이프 사이클

 

  1.  클라이언트가 URI로 JSP 파일을 서버에 요청
  2.  톰캣이 서버에 해당 JSP 파일이 있다면 JSP파일 -> JAVA파일 -> JAVA파일 컴파일 -> 서버 메모리에 로드
  3.  init() 메서드 호출 -> service() 메서드 호출 -> HTTP response 로 응답

 

(jsp)자바파일의 변경이 없다면 -> 기존 메모리에 있는 instance service()로 바로 응답

(jsp)자바파일의 변경이 있다면 -> 기존 instance destroy() 메모리 해제 -> instance 새로 생성 -> init() -> service()

 

톰캣이 jsp 파일을 servlet instance로 만들어서 요청에대한 응답을 한다.

 


 

작성한 jsp 파일

 

 


 

톰캣이 생성한 jsp 파일.java

service() 메서드 일부

 

 

톰캣이 작성된 jsp 파일을 java class(servlet)으로 변환하고, service()메서드를 통해 요청을 처리한 후 응답한다.

 


Servlet

 

HTTP 의 request 를 처리하고 response를 돌려주는 동적인 처리를 위한 자바 기술

 

톰캣이 jsp를 class로 만들고 이 class는 요청을 처리하므로 사실 jsp는 servlet이다.

 - jsp보다 servlet이 먼저 등장했으며, servlet에서의 html 처리가 불편하여 jsp가 등장

 - jsp는 서버에서 데이터를 렌더링하여 html을 만들어서 전달하므로 Server Side Rendering(SSR)이라 한다.

 - 클라이언트에서 데이터를 받아 처리하는 것은 Client Side Rendering(CSR) - Vue, React

 

jsp를 이용하지 않고 직접 servlet에 HTML을 작성할 수도 있다.

 - 직접 작성한 servlet을 이용하게 되면 클라이언트의 요청을 jsp를 거치지 않고 servlet이 직접 받을 수 있다.

 

jsp파일은 view에 집중할 수 있게 되고,

작성한 servlet은 요청에 대한 로직을 처리하는 controller 역할만을 하게되어

jsp파일 내에서 혼합되어 처리되던 html코드와 자바 로직 코드 부분을 분리시켜 MVC 패턴을 적용시킬 수 있다.

 


 

Dispatcher Servlet

 

URL를 통해 서버에 요청이 오면 매핑된 servlet이 해당 요청을 받아준다.

이러한 요청에 맞는 servlet들을 일일이 작성해주어야 했는데 이 부분을 한곳에서 관리하고자 front controller라는 개념이 등장했다.

front controller는 한곳에서 URL과 controller를 매핑해주며, 요청에 위임할 controller에게 다시 요청한다.

spring framework은 dispatcher servlet으로 MVC패턴을 쉽게 구현할 수 있게 틀을 제공해준다.

 


 

클라이언트가 서버에게 HTTP 요청을 하면

 

요청을 받게되면 Servlet Container가 HttpServletReqeust, HttpServletResponse 객체 생성

Dispatcher Servlet으로 해당 URL에 맞는 Controller를 찾아서 비즈니스 로직 수행

이때 Controller에서 HttpServletReqeust의 값을 이용하여 로직 처리

View Resolver로 해당 view를 찾아 HttpServletReqeust, HttpServletResponse에 결과를 View에 렌더링한 후 HTTP header, body 응답

 

 

 

 

 


참고

 

https://www.theserverside.com/feature/Understanding-How-the-Application-Servers-Web-Container-Works

 

Understanding How the Application Server's Web Container Works

To understand how to do proper application server development, you need to understand how the two basic containers of an application server work, namely the Web container and the EJB container. This article will take a look at how a client application inte

www.theserverside.com

 

반응형

'프로그래밍 > Servlet \ JSP' 카테고리의 다른 글

서블릿/JSP  (0) 2022.07.19
반응형

 

https://www.amitph.com/spring-entity-to-dto/

 

Convert Entity To DTO In Spring REST API

A tutorial on How to Entity to DTO Conversion and DTO to Entity Conversion in a Spring REST API manually as well as by using Model Mapper.

www.amitph.com

 

변환하는 방법을 소개하는 좋은 글이 있어서 남긴다.

 

  • 생성자를 사용하는 방법
  • 메서드를 사용하는 방법
  • ModelMapper를 사용하는 방법
  • MapStruct를 사용하는 방법

 

메서드를 사용하는 방법이 직관적

만약 변경해야할 필드가 많다면 ModelMapper, MapStruct를 사용하는 것이 용이할 것 같다.

 


MapStruct 사용

 

 

compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

implementation 'org.mapstruct:mapstruct:1.4.2.Final'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.4.2.Final'

 

gradle에서 mapstruct가 lombok과 이슈를 일으킨다.

lombok이 mapstruct보다 위에 있으면 해결된다.

 

 

 

 

@Mapper
public interface UserMapper {

    UserMapper mapper = Mappers.getMapper(UserMapper.class);

    // dto -> entity
    @Mapping(target = "userAge", source = "age")
    @Mapping(target = "name" , source = "name", defaultValue = "Park")
    UserEntity userDtoToEntity(UserDto userDto);


    @Mapping(target = "age", source = "userAge")
    UserDto userEntityToDto(UserEntity userEntity);

}

@Mapper 

구현체는 mapstruct가 만들어준다.

import할 때 Mybatis의 @Mapper와 구분

 

@Mapping

필드명 불일치를 해결할 수 있다.

defaultValue도 설정할 수 있다.

 

 

 

 

 

@Test
void UserDtoToEntity(){
    UserDto userDto = new UserDto(1, "cha", "email", 30);
    UserEntity userEntity = UserMapper.mapper.userDtoToEntity(userDto);

    System.out.println(userEntity);
}

 

 

 


참고

 

 

 

https://mapstruct.org/documentation/stable/reference/html/

 

MapStruct 1.5.2.Final Reference Guide

If set to true, MapStruct in which MapStruct logs its major decisions. Note, at the moment of writing in Maven, also showWarnings needs to be added due to a problem in the maven-compiler-plugin configuration.

mapstruct.org

 

 

http://modelmapper.org/getting-started/

 

ModelMapper - Getting Started

Getting Started This section will guide you through the setup and basic usage of ModelMapper. Setting Up If you’re a Maven user just add the modelmapper library as a dependency: org.modelmapper modelmapper 3.0.0 Otherwise you can download the latest Mode

modelmapper.org

 

 

https://blog.naver.com/PostView.nhn?isHttpsRedirect=true&blogId=kbh3983&logNo=220988245343 

 

[JAVA] ModelMapper Customizing

주의!! 일부 버전에서 Custom Mapping 이 됬다 안됬다하는 버그가 있음 아오....하루종일을 날렸네........

blog.naver.com

 


 

반응형
반응형

 

h2를 사용하다가 오류가 전혀 없어 보이는데 문법 오류가 났다.

 

h2에서는 mysql 문법을 지원하지 않아서 나는 오류다.

 


 

 

첫 연결시에 JDBC URL 마지막에 ;mode=mysql를 입력해주면 mysql 문법을 사용할 수 있다.

 

 


 

 

data.sql 을 spring boot 2.5부터 사용할 때 추가해줘야한다.

 

defer-datasource-initialization: true  # data.sql 사용할 때 spring boot 2.5부터 추가
반응형

' > 오류 모음' 카테고리의 다른 글

[DataBase] 오류  (0) 2022.06.29
[Spring boot] 오류 모음  (0) 2022.05.02

+ Recent posts