JPA 란 "객체와 관계형 데이터베이스 테이블이 어떻게 매핑되는지를 이해하는 것"

 

 

단방향

JPA 에서는 기본적으로 두 엔티티 사이의 연관 관계를 단방향으로 정의한다.

이 상태에서는 한 쪽 엔티티는 연관 관계인 엔티티 객체를 조회할 수 있으나, 반대쪽 엔티티 객체는 어떤 엔티티 객체와 연관관계를 갖는지 알 수 없다.


양방향 연관 관계의 규칙

  • 연관 관계를 갖는 두 객체 중 하나를 연관 관계의 주인으로 지정
  • 연관 관계의 주인만이 외래키를 관리(삽입, 수정, 삭제)
  • 주인이 아닌 쪽은 읽기만 가능
  • 주인은 mappedBy 속성을 사용하지 않음
  • 주인이 아닌 쪽은 mappedBy 속성을 사용하여 주인 지정

@Entity   

테이블과 매핑할 엔티티

 

@Table 

엔티티와 매핑할 테이블 

 

@Id

데이터베이스 테이블의 기본 키와 객체의 필드를 매핑 ( 직접 할당)

 

@GeneratedValue 

기본키를 자동으로 생성해주는 애노테이션

@GeneratedValue(strategy = GenerationType.IDENTITY : 기본 키 생성을 데이터베이스에 위임

@GeneratedValue(strategy = GenerationType.SEQUENCE : 유일한 값을 순서대로 생성

 

@Column

 

@ManyToOne  @OneToMany

 

@JoinColumn

Entity의 연관관계에서 외래 키를 매핑하기 위해 사용.

name 속성 : 매핑할 외래 키의 이름 지정

그리디

탐욕 알고리즘.

현재 상황에서 지금 당장 좋은 것만 고르는 방법으로 현재의 선택이 나중에 미칠 영향은 고려하지 않는다.

 

 

코딩테스트에서의 그리디

문제를 풀 수 있는 최소한의 아이디어를 떠올릴 수 있는 능력을 요구한다.

 

 

ex)

'거스름돈' 문제 (그리디 알고리즘의 대표 문제)

500원, 100원, 50원의 동전으로 거스름돈을 내어줄 때 최소의 동전 갯수로 거스름돈을 내어주는 방법은?

 

해결방법

가장 큰 화폐 단위부터 돈을 거슬러 준다.

 

 

 

다음과 같이 각 문제에서의 아이디어를 떠올릴 수 있고 이것이 정당한 지 검토할 수 있으면 그리디 문제를 풀 수 있다.

 

 


내가 백준 그리디 문제들을 풀면서 느낀 점

 

지금 상황에서 가장 좋은 것을 고르는 그리디의 특성상 문제의 흐름을 순응적으로, 그대로 따라가기 보다는 

주어진 조건에서 가장 빠르게, 정확하게 문제를 해결할 수 있는 모든 방법을 고려해 보아야 한다.

 

예를들어, 백준 11047번도 주어진 단위의 동전들으로 최소 개수를 고르는 문제이며 for문을 단위가 큰 값(동전 리스트의 뒷쪽 부터 시작한다면 시간 초과를 피할 수 있다)

나는 이 문제를 1원부터 돌면서 4200원에 맞는 가장 큰 단위(1000원)를 찾도록 코드를 작성하였더니 시간초과가 나왔다.

 

 

 

비단 이 문제 뿐 아니라 모든 코테 문제에서 여러가지 시야를 가질 수 있도록 더 훈련해야 할 것 같다.

문제 해석

나이와 이름을 pair로 입력 받고 정렬해야하는 문제

 

 

 

stable sort

#include <algorithm> 헤더에 들어있는 sort 기법으로, 원래의 순서를 손상시키지 않으면서 정렬하는 기능

 

이 기능을 통해 나이가 같은 경우 입력한 순서대로 정렬해야하는 조건을 충족시킬 수 있다.

 

 

 

코드

#include<iostream>
#include<utility>
#include<algorithm>
#include<string>
using namespace std;

bool compare(const pair<int,string>& a , const pair<int,string>& b) {
    
    return a.first < b.first;  
}

int main() {
    int n;
    cin>>n;
    pair<int,string> p[n];
    for(int i=0;i<n;i++) {
        int a;
        string b;
        cin>>a>>b;
        p[i].first = a;
        p[i].second = b;
    }
    stable_sort(p, p +n,compare);
    for(int i=0;i<n;i++) {
        cout<<p[i].first<<' '<<p[i].second<<'\n';
    }
    return 0;
}

이 포스팅은 인프런 김영한님의 스프링입문 강의 중 섹션1 빌드하고 실행하기 중 발생한 에러에 대한 내용입니다!

 

빌드하고 실행하기!

인텔리제이를 사용해서 실행하지 말고 cmd 창에서 빌드하고 실행해보는 방법

 

 

<윈도우 환경>

 

1. 코드가 있는 경로로 cmd 창 열기

2. gradlew 입력  (gradlew 를 입력하면 gradlew.bat가 실행된다고 한다)

3. gradlew build 입력

  -> 문제 발생!

다음과 같이 Execution failed for task ':test'  그리고 파일의 build폴더안의 ~~~~경로의 index.html에서 문제가 발생했다고 한다. 흠.. 저 경로의 해당 파일은 만진적도 없는데 말이다. 강의를 그대로 따라하고 있었는데 왜 에러가 뜬건지 알 수 없지만

 

여기 저기 구글링을 해본 결과

gradlew build 를 입력할 때 --debug 를 추가하면 해결된다고 한다. 

 

3. gradlew --debug build 입력!

수많은 디버깅 코드들과 함께 빌드가 정상 작동되고

 

4. cd build/libs  입력(libs 폴더로 이동하기)

5. java -jar hello.spring-0.0.1-SNAPSHOT.jar 입력하면 실행 성공!

  (참고로 리눅스에서 내가 습관적으로 사용하는 ls 는 윈도우에서 dir 이다)

localhost:8080 으로 이동해보면 성공적으로 실행되는 것을 확인할 수 있다.!!!

 

백준 1463번 C++ 풀이

다이나믹 프로그래밍 문제

3가지 연산이 가능한데 입력 받은 n을 3가지 연산을 최소로 사용해서 1로 만들어야 한다.

 

연산을 최소로 사용해야 한다는 부분이 포인트다.

bottom-up 방식의 dp를 이용해 풀 수 있다.

 

입력받는 값 n의 연산 횟수만을 출력하면 되지만 1부터 n까지 각각의 값들의 연산 횟수를 모두 알아야 한다.

 

 

dp[ x ] = y   에서 y는 x의 연산횟수를 의미한다. 

 

for문 안에서 min 연산을 통해 최소의 연산 횟수를 유지할 수 있게 한다.

 

"1을 뺀다." 라는 연산을 적용해 dp[i] 는 dp[i-1] 보다 1 큰 값을 입력한다.

예를 들어 n= 10 일때 

10 - 1  ->9     연산 1회  

             +       9의 연산 횟수  => 10의 연산 횟수   가 되기 때문.

 

그리고 만약 2 또는 3으로 나눠진다면 min을 사용해 나누기를 사용했을 때의 연산횟수와 기존의 연산횟수 중 최솟값을 구할 수 있다.

 

스택(STACK)

한쪽 끝에서만 자료를 넣고 뺀다.

가장 최근에 들어온 자료가 가장 먼저 나가는 방식. LIFO(Last In First Out 방식)

 

top = 스택의 맨 위 요소, 가장 최근에 삽입한 값

stack.push( ) = top에 새로운 데이터 추가

stack.pop( ) = top 삭제

 

삽입, 삭제의 시간 복잡도는 O(1)

 

 

c++ stl stack 존재

 

#include <stack>

stack<int> st;

st.push(10);

st.pop();

st.top();

st.size();

st.empty();

 

 

 

큐(QUEUE)

양쪽 끝에서 데이터의 삽입과 삭제가 각각 이루어진다.

가장 먼저 들어왔던 데이터부터 삭제되는 선입선출 방식.FIFO(First In First Out)

 

queue.push( ) = back쪽에 새로운 데이터 추가

queue.pop( ) = front 데이터 삭제

queue.front( ) = 가장 오래된 데이터

queue.back( ) = 가장 최근에 들어온 데이터

 

 

c++ stl queue 존재

#include <queue>

queue<int> q;

q.push(10);

q.pop();

q.front();

q.back();

q.size();

q.empty();

상속이란?

: 이미 구현된 상위 클래스를 하위 클래스에 상속하는 것이다. 상속을 해주는 클래스를 부모클래스라고 하며 상속받는 클래스를 자식 클래스라고 한다.

 

 

 

 

상속의 방법

: 예를 들어, 모든 고객인 customer 클래스는 vip고객인 vipcustomer 클래스의 상위 클래스

 

class Customer {

}

 

 

class VIPCustomer extends Customer {

}

 

 

 

 

접근 제한자의 가시성

public 동일 패키지나 외부 패키지에서 모두 제한없이 사용할 수 있다.
protected 동일 패키지 내부 + 외부 패키지 중 상속받은 경우에 사용할 수 있다.
default (따로 명시하지 않은 경우) 동일 패키지 내부에서만 사용가능하다.
private 본인 클래스 내부에서만 사용 가능하다.

 

 

상속에서 주의할 점!

: 하위클래스를 호출하면 자동적으로 상위클래스도 함께 호출된다. 

하위클래스 생성자를 호출하면 상위클래스의 생성자가 호출된 뒤 하위클래스의 생성자가 호출된다.

 

오버라이딩

: 상속 관계의 부모클래스에서 이미 정의된 메서드를 자식 클래스에서 선언부가 같게 동작만 재정의하는 것

 

super() 예약어

:부모 클래스를 호출하는 예약어 , 직접 입력하지 않는 경우 자동적으로 super()를 호출한다.

 

 

업캐스팅

: 자식 클래스가 부모 클래스 타입으로 캐스팅 되는 것

 

자식 클래스에만 존재하는 속성이나 메소드는 실행하지 못한다.

자식 클래스에서 오버라이딩한 메서드가 있을 경우, 부모 클래스의 메서드가 아닌 오버라이딩 된 메서드가 실행되게 된다.

 

 

 

내가 헷갈렸던 부분!!!

하위클래스의 메소드는 실행하지 못하지만 오버라이딩되었을때는 상위, 하위클래스 중 하위클래스의 메서드가 실행된다.

자식클래스의 메서드를 사용하는 이유 = 오버라이딩 특성 상 코드가 실행하는 런타임 환경에서 동적으로 바인딩 되었기 때문

 

바인딩은 무엇인가

바인딩 Binding : 메서드 호출과 메서드 본문의 연결

 

프로그램의 실행되는 과정에서 바인딩되는 것을 동적 바인딩(dynamic binding)

실행 이후에 값이 확정되면 동적 바인딩(dynamic binding)

대표적인 예시로 Method Overriding - 부모와 자식 Class에 모두 동일한 Method가 존재, 오직 실행 시점에 타입이 결정되어 해당 타입의 Method가 실행됨

 

 

다형성

: 하나의 코드가 여러 자료형으로 구현되어 실행되는 것

 

다운캐스팅

: 상위 클래스로 형 변환되었던 하위 클래스를 다시 우너래 자료형으로 현 변환하는 것

 

 

 

 

 

 

 

 

 

얼마 전에 드디어! 백준 실버 등급에 도달했다.

작고 소중한 나의 실버 등급

브론즈에 있을 때는 실버가 그렇게 예뻐보였는데 실버에 오니 골드가 너무 멋있어 보인다. 골드 다는 그날까지 열심히 꾸준히 풀어야지

 

 

지난주에 개강도 하고 며칠 못 풀다가 오늘 실버5문제로 다시 백준 풀기를 이어가 줬다.

 

 

 

백준 1978번

나는 등급 별로 푼 사람 수가 많은 순서대로 문제를 푸는데

오늘 푼 문제는 실버치고 그다지 어렵지 않은 문제라서 후딱 이해하고 풀어낼 수 있었다.

 

주어진 숫자가 소수인 지 아닌 지 체크하는 방법만 알고 있다면 풀 수 있는 문제!

 

소수란 1과 자기 자신만을 약수로 가지는 수이다.

예를들어 2,3,5,7,11,13 등등등이 있겠지

 

문제를 보자마자 소수의 특징을 이용해서 소수 갯수를 카운트할 수 있는 방법이 있을텐데 싶었다.

 

1과 자기 자신만을 약수로 가져야 하므로 2 ~ 자기자신-1 인 수로 나누었을 때는 나머지가 0이면 안된다.

 

이 방법을 적용해서 소수의 갯수를 세는 코드를 작성해 보았다.

 

key가 1일 때가 소수임을 의미하는 때 이다.

 

처음에는 위와 같이 코드를 짰다. 2부터 a-1까지 중에 나머지가 0인 경우가 있다면 체크하는 방법이었다.

이렇게 코드를 짜면서 자연수 1을 입력하는 경우에는 for문에서 어떻게 돌게 되는 지 헷갈려서 a가 1인 경우를 따로 빼서 작성하였다.

 

 

 

 

그리고 구글링하여 아래 코드 같은 방법도 찾아냈는데 훨씬 깔끔하게 작성된 것 같아서 아래와 같은 방법으로도 구현해 봤다. 소수의 정의인 1부터 자기자신까지의 나머지를 모두 체크하고 0인경우가 2번인 경우에만 갯수를 센다.

 

+ Recent posts