no image
[JPA] 영속성 관리, 영속성 컨텍스트
웹 어플리케이션에 엔티티매니저 팩토리는 하나만 만들고, 요청이 들어올때마다 엔티티 매니저를 생성한다. 그리고 DB 내부적으로 connectionPool을 사용한다. 영속성 컨텍스트(Persistence Context) ? 영속성 컨텍스트란 "엔티티를 영구 저장하는 환경"이라는 뜻이다. 엔티티 매니저로 엔티티를 저장하거나 조회하면 엔티티 매니저는 영속성 컨텍스트에 엔티티를 보관하고 관리한다.EntityManager.persist(entity);사실 위 코드는 DB에 엔티티를 저장한다기 보다는 영속성 컨텍스트를 통해 엔티티를 영속화 한다는 의미이다. ( 즉, 영속성 컨텍스트에 저장 한다는 의미이다. ) 영속성 컨텍스트는 논리적인 개념이며, 눈에 보이지 않는다. 엔티티 매니저를 통해서 영속성 컨텍스트에 접근한..
2024.05.03
JPA
[JPA] Entity와 EntityManager, EntityManagerFactory
EntityDB에 member라는 테이블이 있고, 해당 테이블의 스키마가 다음과 같다고 해보자.create table Member (id bigint not null, name varchar(255), primary key(id));그렇다면 엔티티는 다음과 같이 만들 수 있다. 엔티티는 JPA가 관리할 객체이며, DB의 테이블과 매핑된다.import jakarta.persistence.Entity;import jakarta.persistence.Id;@Entitypublic class Member { @Id private Long id; private String name; //Getter, Setter ...}기본적으로 JPA는 모든 필드를 불러오게 끔 구현되어 있다. ..
2024.05.03
JPA
no image
[JPA] 데이터베이스 방언, Dialect
JPA는 특정 데이터베이스에 종속적이지 않은 기술이다. 따라서 다른 데이터베이스로 손쉽게 교체할 수 있다.  SQL은 표준 SQL인 ANSI SQL이 있으며, ANSI SQL 이외에 각 DBMS Vendor인 MS-SQL, Oracle, MySQL, PostgreSQL에서 자신만의 기능을 추가한 SQL이 있다. ANSI SQL이 모든 DBMS에서 공통적으로 사용가능한 핵심 표준 SQL이지만, 여러 제품의 DBMS에서는 자신만의 독자적인 기능을 위해 추가적인 SQL을 만들었다. 즉,  각 데이터베이스가 제공하는 SQL 문법과 함수가 조금씩 다르다는 문제점이 있다. 예를 들면 다음과 같은 차이점들이 존재한다. 데이터 타입 : 가변 문자 타입으로 MySQL은 VARCHAR, 오라클은 VARCHAR2를 사용한다..
2024.05.03
JPA
정보처리 기사 응시자격 서류, 4학년 휴학생
일단 글을 작성하기 앞서, 필자는 컴퓨터공학 계열 학생이며, 3학년 2학기 까지의 과정을 마친 후 4학년 1학기 등록금을 납부 후 휴학을 한 상태이다. 그런데 휴학 증명서를 뽑아 보니, 3학년으로 찍혀있었고.. 학교 측과 큐넷에 문의해보니 학력변동 확인서를 작성후 교무처장 직인을 받으면 된다는 답을 얻게 되었다! 정보처리 기사 응시자격 서류 준비 실기를 접수하기 전에 응시자격 서류 제출은 필수이다. 만약 이 기간에 서류를 제출하지 않으면, 필기시험을 봤던것도 무효이며 실기를 접수할 수 없게 된다. 현재 나는 4학년 등록을 한 후 휴학을 신청했지만, 휴학증명서에 3학년이라고 찍혀있었다. 블로그에 찾아보니 다들 4학년 등록 후 휴학을 하면, 4학년이라 찍히기 때문에 정처기를 볼 수 있다 라고 했었기에.. 나..
2024.03.19
no image
2024 정보처리기사 1회 필기 합격 후기, 공부방법 (Feat 4학년 휴학생, 전공자)
2024년 3월 4일에 시행한 정보처리기사 1회 필기 시험을 보고 왔다 ! 떨어지면... 올해 계획한 일정들이 전부 꼬여버리기 때문에 꼭 붙어야 된다는 생각을 가지고 준비했다. 한번도 자격증 시험을 본 적이 없었고 실기도 같이 준비하자 라는 마인드로 기간을 길게 잡고 공부했다. 그리고 필기 접수를 할 당시에 사전 정보 입력도 하고, 시간 딱 맞춰서 1시에 들어가서 시험장 찾기를 시도했으나.. 내가 살고 있는 지역에는 시험장이 없었다^^ 그 와중에 그나마 가까운 시험장은 이미 다 찬 상태이고.. 그래서 하다하다 결국 이태원 역에 있는 한국폴리텍대학에서 시험을 치게 되었다ㅜㅠ.. ( 참고로 아침에 차 밀릴까봐 6시 반에 집에서 나와서 시험장으로 갔다.. ) 그래서 시험 난이도는 어땠는가 하면 내 기준으로 쉬..
2024.03.19
[JAVA] 백준 p1934 - 최소 공배수
1934번: 최소공배수 두 자연수 A와 B에 대해서, A의 배수이면서 B의 배수인 자연수를 A와 B의 공배수라고 한다. 이런 공배수 중에서 가장 작은 수를 최소공배수라고 한다. 예를 들어, 6과 15의 공배수는 30, 60, 90등이 있 www.acmicpc.net 단순하게 최소 공배수를 구하는 문제이다. 이 문제에서 포인트는 최소 공배수는 A와 B 가 주어졌을 때 "A*B / 최대공약수" 를 계산해 구할 수 있다. 는 것이다. 결국 유클리드 호제법을 이용해서 최대 공약수를 구하면 해결 할 수 있다. 유클리드 호제법에 관해 정리해 둔 글이다. [JAVA] 유클리드 호제법 - 최대 공약수 구하기 최대 공약수를 구하는 방법 일반적으로 최대 공약수를 구하려고 하면 소인수 분해를 이용해서 공통된 소수들의 곱으로..
2024.02.17
[JAVA] 유클리드 호제법 - 최대 공약수 구하기
최대 공약수를 구하는 방법 일반적으로 최대 공약수를 구하려고 하면 소인수 분해를 이용해서 공통된 소수들의 곱으로 표현한다. 그러나 소인수 분해를 위해 소수를 먼저 찾아야 하고, 찾은 소수가 두개의 수를 공통적으로 나눌 수 있는지 확인해야 하기 때문에 이는 효율적이지 않다. 유클리드 호제법을 이용하면 더 간단한 방법으로 최대 공약수를 구할 수 있다. 유클리드 호제법(Euclidean Algorithm) 두 개의 자연수(두 개의 다항식)의 최대 공약수를 구하는 알고리즘이다. 호제법이란 말은 두 수가 서로 상대방 수를 나누어 결국 원사는 후를 얻는 알고리즘을 나타낸다. 2개의 자연수(또는 정식) a,b에 대해서 a를 b로 나눈 나머지를 r이라고 하면( 단, a>b ) a와 b의 최대 공약수는 b 와 r의 최대..
2024.02.17
[JAVA] 프로그래머스 - 소수 만들기
https://school.programmers.co.kr/learn/courses/30/lessons/12977 프로그래머스 코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요. programmers.co.kr 문제를 단순하게 정리하자면, 주어진 문제는 배열에 있는 숫자들 중에 3개를 골라 더했을때 소수가 되는 경우의 개수를 구하면 되는 문제이다. 처음에 딱 보고 든 생각은 다음과 같다. 3개의 수는 어떻게 뽑을 것인가..? 방법 1. ) 사실 단순한 방법은 for문을 3번 돌리면서 값을 구한뒤 , 그 값이 소수인지를 판별하는 것이다. 방법 2. ) 배열의 조합 값들을 모두 찾아내서 정리한뒤 ( 재귀나 ..
2024.02.15

웹 어플리케이션에 엔티티매니저 팩토리는 하나만 만들고, 요청이 들어올때마다 엔티티 매니저를 생성한다. 그리고 DB 내부적으로 connectionPool을 사용한다.

 

영속성 컨텍스트(Persistence Context) ?

 

영속성 컨텍스트란 "엔티티를 영구 저장하는 환경"이라는 뜻이다. 엔티티 매니저로 엔티티를 저장하거나 조회하면 엔티티 매니저는 영속성 컨텍스트에 엔티티를 보관하고 관리한다.

EntityManager.persist(entity);

사실 위 코드는 DB에 엔티티를 저장한다기 보다는 영속성 컨텍스트를 통해 엔티티를 영속화 한다는 의미이다. ( 즉, 영속성 컨텍스트에 저장 한다는 의미이다. )

 

영속성 컨텍스트는 논리적인 개념이며, 눈에 보이지 않는다. 엔티티 매니저를 통해서 영속성 컨텍스트에 접근한다. 

 

엔티티의 생명주기

 

엔티티에는 4가지 상태가 존재한다.

  • 비영속 ( new/transient ) : 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
  • 영속 ( managed ) : 영속성 컨텍스트에 관리 되는 상태       // persist 하고 나면 영속 상태가 된다.
  • 준영속 ( detached ) : 영속성 컨텍스트에 저장되었다가 분리된 상태
  • 삭제 ( removed ) : 삭제된 상태

엔티티의 생명 주기

 

비영속

 

엔티티 객체를 생성하면, 이는 순수한 객체 상태이며 아직 저장하지 않았기 때문에 영속성 컨텍스트와 관련이 없다. 이를 비영속 상태라고 한다.

//EntityManager.persist(member)를 호출하기 전, 비영속 상태이다.
            Member member = new Member();
            member.setId(100L);
            member.setName("HelloJPA");

비영속

영속

엔티티 매니저를 통해 엔티티를 영속성 컨텍스트에 저장한다. 영속성 컨텍스트가 관리하는 엔티티를 영속 상태라고 한다. 결국 영속 상태라는 것은 영속성 컨텍스트에 의해 관리된다는 뜻이다. 그리고 EntityManager.find()나 JPQL을 사용해서 조회한 엔티티도 영속성 컨텍스트가 관리하는 영속 상태이다. 

//객체를 생성한 상태 (비영속)
Member member = new Member();
member.setId("member1");
member.setUsername(“회원1”);

EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

//객체를 저장한 상태 (영속 상태)
em.persist(member);

차영속 상태 ( 영속성 컨텍스트에 의해 관리되는 상태 )

준영속

영속성 컨텍스트가 관리하던 영속 상태의 엔티티를 영속성 컨텍스트가 관리하지 않으면 준영속 상태가 된다. 

엔티티를 준영속 상태로 만드려면, 엔티티 매니저의 detach() 메서드를 호출하면 된다. 아니면 엔티티 매니저의 close() 메서드를 호출해서 영속성 컨텍스트를 완전히 닫아버리는 방법도 있다. 아니면 clear()를 호출해서 영속성 컨텍스트를 초기화 하는 방법도 있다.

삭제

엔티티를 영속성 컨텍스트와 데이터베이스에서 삭제한다.

EntityManager.remove(member); //객체를 삭제한 상태 (삭제)

 

영속성 컨텍스트의 특징

 

영속성 컨텍스트와 식별자 값

영속성 컨텍스트는 엔티티를 식별자 값(@Id로 테이블의 기본 키와 매핑한 값)으로 구분한다. 따라서 영속상태는 식별자 값이 반드시 있어야 한다. 식별자 값이 없다면 예외가 발생한다.

 

영속성 컨텍스트와 데이터베이스 저장

영속성 컨텍스트에 엔티티를 저장하면 바로 데이터 베이스에 저장되는 것이 아니다. 보통은 트랜잭션을 커밋하는 순간 영속성 컨텍스트에 새로 저장된 엔티티를 데이터베이스에 반영하는데 이것을 플러시(flush)라고 한다.

 

영속성 컨텍스트의 이점 -> 애플리케이션과 DB 사이에 중간 계층이 하나 있는 것과 같다.

  • 1차 캐시
  • 동일성 보장 
  • 트랜잭션을 지원하는 쓰기 지연
  • 변경 감지 (Dirty Checking)
  • 지연 로딩 (Lazy Loading)

 

엔티티 조회, 1차 캐시

 

영속성 컨텍스트는 내부에 1차 캐시라는 것이 존재한다. 영속상태의 엔티티는 모두 1차 캐시에 저장된다. DB의 PK값을 @Id로, Entity 객체 값을 Map 형태로 1차 캐시에 저장하고 있는 것이다. 아래 코드를 실행하면, 1차 캐시에 아래와 같이 저장되게 된다.

//엔티티를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
//엔티티를 영속, 1차 캐시에 저장됨
em.persist(member);

그리고 추후에 해당 객체를 찾게 된다면, JPA는 DB에서 값을 찾아오는 것이 아니라, 1차 캐시에서 값을 찾아온다.

//1차 캐시에서 조회
Member findMember = em.find(Member.class, "member1");

만약, 1차 캐시에 찾는 값이 없다면?

Member findMember2 = em.find(Member.class, "member2");

엔티티 매니저는 데이터 베이스를 조회해서 엔티티를 생성한다. 그리고 이를 바로 반환하는 것이 아니라, 1차 캐시에 저장하고 영속 상태의 엔티티를 반환한다. 따라서 이후에 또 member2 엔티티를 조회한다면, 1차 캐시에서 바로 불러올 수 있다. 

 

그러나 데이터 베이스 하나의 트랜잭션에서만 이점을 얻을 수 있기에 사실 이 기능은 큰 도움이 되지 않는다. 왜냐하면 엔티티 매니저는 하나의 요청 단위로 생성하게 되며, 요청이 끝나면 엔티티 매니저를 지우게 된다. 엔티티 매니저를 지우게 되면 해당 영속성 컨텍스트도 지워지기 때문에 큰 도움이 되지 않는 것이다.

import jakarta.persistence.*;

import java.util.List;

public class JpaMain {

    public static void main(String[] args) {

        //factory는 애플리케이션 로딩 시점에 딱 한번 만들어야 됨.
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); //persistence-unit에서 지정함 이름을 넘긴다.
        EntityManager em = emf.createEntityManager(); //엔티티 매니저 하나 받음 ( 마치 자바 컬렉션이라고 생각 ( 내 객체를 대신 저장해주는 ))
        //code
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        try {

            Member findMember1 = em.find(Member.class, 100L);
            Member findMember2 = em.find(Member.class, 100L);

            tx.commit();//트랜잭션 커밋 시, 쿼리가 날라가게 된다.
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
        emf.close();
    }
}

이 경우에도, 새로운 영속성 컨텍스트가 만들어졌기 때문에 첫번째 find 호출 시, findMember1의 경우 1차 캐시에 값이 없기 때문에 DB에서 값을 찾아오게 된다. 따라서 select 쿼리가 나가게 되고, 찾아온 값을 1차 캐시에 저장후 반환하게 된다.

 

이후부터는 똑같은 값을 조회할 경우, 1차 캐시에 등록되어 있기 때문에 select 쿼리가 나가지 않는다.

영속 엔티티의 동일성 보장

동일성이란, 두 객체의 인스턴스가 같은 것 즉, 참조값이 같음을 의미한다. em.find(Member.class, "member1")를 아무리 반복해서 호출해도 JPA는 1차 캐시에 있는 같은 엔티티 인스턴스를 반환한다. 따라서 a와 b는 같은 인스턴스이고 결과는 당연히 true를 반환한다. 따라서 영속성 컨텍스트는 엔티티의 동일성을 보장한다.

 

1차 캐시로 반복가능한 읽기(REPEATABLE READ) 등급의 트랜잭션 격리 수준을 데이터베이스가 아닌 애플리케이션 차원에서 제공한다는 장점이 있다. ( 단, 같은 트랜잭션 안에서 실행시 ) -> 트랜잭션 레벨이 Read Commited 여도 1차 캐시를 이용해 Repeatable read 등급의 이점을 챙길 수 있다. 트랜잭션 격리 수준에 대해 알아보면 좋을 것 같다..

 

엔티티 등록 - 트랜잭션을 지원하는 쓰기 지연

 

엔티티 매니저는 트랜잭션을 커밋하기 전까지 데이터베이스에 엔티티를 저장하지 않고내부 쿼리 저장소에 INSERT SQL을 차곡차곡 모아둔다. 그리고 트랜잭션을 커밋할때  모아둔 쿼리를 데이터베이스에 보내는데 이것을 트랜잭션을 지원하는 쓰기 지연이라 한다. -> 쿼리를 커밋하는 시점에 한번에 날리는 것을 의미한다.

우선 회원 A를 영속화한 후, 영속성 컨텍스트는 1차 캐시에 회원 엔티티를 저장하면서 동시에 회원 엔티티 정보로 등록 쿼리를 만든다. 그리고 만들어진 등록 쿼리를 쓰기 지연 SQL 저장소에 보관한다.

 

그 다음으로는 회원 B를 영속화한 후, 마찬가지로 회원 엔티티 정보로 등록 쿼리를 생성해서 쓰기 지연 SQL 저장소에 보관한다. 현재 쓰기 지연 SQL 저장소에 등록 쿼리가 2건 저장된 것이다.

 

 

 

트랜잭션을 커밋하면 엔티티 매니저는 우선 영속성 컨텍스트를 플러시한다. 플러시는 영속성 컨텍스트의 변경 내용을 데이터베이스에 동기화하는 작업이다. 이때 등록, 수정, 삭제한 엔티티를 데이터베이스에 반영한다.

쓰기 지연 SQL 저장소에 모인 쿼리를 데이터 베이스에 보내는 것이다. 이렇게 영속성 컨텍스트의 변경 내용을 데이터베이스에 동기화한 후에 실제 데이터베이스 트랜잭션을 커밋한다.

 

 

변경 감지 ( Dirty Checking )

 

Jpa는 따로 수정을 위한 메서드가 존재하지 않는다. 그냥 엔티티를 수정하면 된다. (set 메서드 등을 이용해서.. ) 그리고 이것을 변경 감지(Dirty Checking)이라고 한다. 

 

JPA는 트랜잭션을 커밋하는 시점에 내부적으로 flush를 호출하게 된다. flush를 호출하게 되면 엔티티와 스냅샷을 비교하게 된다. 1차 캐시에 스냅샷이라는 것도 있다. ( 값을 읽어온 최초 시점에 그 상태를 스냅샷 떠논 것이다. ) 값을 비교해서 수정된게 있다면, SQL을 만들어서 지연 저장소에 저장해두게 된다. 그리고 그것을 데이터베이스에 쿼리를 날려서 변경하고 최종적으로 커밋을 호출하게 된다.

 

 

플러시

 

영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하는 것을 말한다. ( 영속성 컨텍스트의 쿼리들을 DB에 날리는 것을 의미한다. ) 보통 데이터베이스 커밋이 일어나게 되면, 플러시가 실행된다.

 

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

 

1. em.flush() //직접 호출
2. 트랜잭션 커밋  //플러시 자동 호출된다.
3. JPQL 쿼리 실행 //플러시 자동 호출

import jakarta.persistence.*;

import java.util.List;

public class JpaMain {

    public static void main(String[] args) {

        //factory는 애플리케이션 로딩 시점에 딱 한번 만들어야 됨.
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); //persistence-unit에서 지정함 이름을 넘긴다.
        EntityManager em = emf.createEntityManager(); //엔티티 매니저 하나 받음 ( 마치 자바 컬렉션이라고 생각 ( 내 객체를 대신 저장해주는 ))
        //code
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        try {
            //영속
            Member member = new Member(200L, "member200");
            em.persist(member);

            em.flush(); //플러시 강제 호출

            System.out.println(" ==================== ");
            tx.commit();//트랜잭션 커밋 시, 쿼리가 날라가게 된다.
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
        emf.close();
    }
}

이렇게 하게 된다면 강제로 플러시를 호출하게 된다. 이 경우 커밋 시점시 쿼리를 날리는게 아니라 ====== 전에 쿼리가 날라가게 됨을 콘솔창에서 확인할 수 있다.

1차 캐시에서 조회

플러시를 호출하게 되면, 플러시에 있는 내용들이 사라질까? 아니다. 지연 저장소에 있는 쿼리문들이 날라가는 것이다.

'JPA' 카테고리의 다른 글

[JPA] Entity와 EntityManager, EntityManagerFactory  (0) 2024.05.03
[JPA] 데이터베이스 방언, Dialect  (0) 2024.05.03

Entity

DB에 member라는 테이블이 있고, 해당 테이블의 스키마가 다음과 같다고 해보자.

create table Member (
id bigint not null,
    name varchar(255),
    primary key(id)
);

그렇다면 엔티티는 다음과 같이 만들 수 있다. 엔티티는 JPA가 관리할 객체이며, DB의 테이블과 매핑된다.

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@Entity
public class Member {
    @Id
    private Long id;
    private String name;
    //Getter, Setter ...
}

기본적으로 JPA는 모든 필드를 불러오게 끔 구현되어 있다. 하지만, 모든 케이스에서 id, name 필드를 전부 다 다루지 않을 수 있다. 이 경우에는 id 필드만 다루는 경우도 있을 수 있다. 그런 경우를 대비해서 엔티티 클래스를 하나 더 만들 수 있다.

따라서 테이블은 한 개지만, 엔티티는 경우에 따라서 여러 개를 만들 수 있다고도 한다.

 

 

EntityManagerFactory 생성

 

JPA를 시작하려면 우선 persistence.xml의 설정 정보를 사용해서 엔티티 매니저 팩토리를 생성해야 한다. 이때 Persistence 클래스를 사용한다. 이 클래스는 엔티티매니저팩토리를 생성해서 JPA를 사용할 수 있게 해 준다.

   //factory는 애플리케이션 로딩 시점에 딱 한번 만들어야 됨.
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); //persistence-unit에서 지정함 이름을 넘긴다.
        EntityManager em = emf.createEntityManager(); //엔티티 매니저 하나 받음 ( 마치 자바 컬렉션이라고 생각 ( 내 객체를 대신 저장해주는 ))

 

이렇게 하면 META-INF/persistence.xml에서 이름이 hello인 영속성 유닛(persistence-unit)을 찾아서 엔티티매니저팩토리를 생성한다.  아래는 persistence.xml 파일의 일부이다. 빌드 시스템을 gradle로 할 경우  src/main/resources/META-INF 폴더를 만들어 persistence.xml 파일을 만들고 아래 내용으로 설정을 해주면 된다. 그리고 엔티티를 class로 명시해 주어야 하다.

 

<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.1">
    <persistence-unit name="hello">
        <class>Member</class>
        <properties>
            <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
            <property name="javax.persistence.jdbc.user" value="sa"/>
            <property name="javax.persistence.jdbc.password" value="비밀번호를 입력해주세요"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test"/>
            <!--현재 사용할 데이터베이스의 방언을 선택한다. 이 부분만 바꾸면 자바코드를 바꾸지 않아도 다른 회사의 DB를 쓸 수 있다.-->
            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
 
            <!--옵션, 이지만 JPA가 어떤 SQL을 만들어내는지 보고 싶으면 넣자.-->
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.format_sql" value="true"/>
            <property name="hibernate.use_sql_comments" value="true"/>
            <property name="hibernate.id.new_generator_mappings" value="true"/>
        </properties>
    </persistence-unit>
</persistence>

 

그리고 maven 프로젝트로 할 경우 댜음과 같이 설정해 주면 된다. 

 

<persistence-unit name="hello"> <!-- 이름이 hello인 영속성 유닛 -->
        <properties>
            <!-- 필수 속성 -->
            <!--데이터베이스 접근 정보-->
            <property name="jakarta.persistence.jdbc.driver" value="org.h2.Driver"/>
            <property name="jakarta.persistence.jdbc.user" value="sa"/>
            <property name="jakarta.persistence.jdbc.password" value=""/>
            <property name="jakarta.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>

            <!-- 옵션 -->
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.format_sql" value="true"/>
            <property name="hibernate.use_sql_comments"  value="true"/>
            <property name="hibernate.hbm2ddl.auto" value="create" />
        </properties>
    </persistence-unit>

 

즉 이렇듯, gradle 시스템에서나, maven 빌드 시스템에서나 JPA는 persistencexml을 통해 필요한 설정 정보를 관리한다.persistence.xml의 정보를 읽어서 JPA를 동작시키기 위한 객체를 만들고 JPA 구현체에 따라서는 커넥션 풀도 생성해야 하기 때문에 엔티티 매니저를 생성하는 비용은 매우 크다. 따라서 엔티티 매니저 팩토리는 하나만 생성해서 애플리케이션 전체에서 공유해야 한다. 

 

 

EntityManager 생성

엔티티매니저팩토리를 생성했다면, 이를 이용해서 엔티티 매니저를 생성해야 한다. 

엔티티 매니저를 이용해서 엔티티를 데이터베이스에 등록/수정/삭제/조회할 수 있다. 따라서 JPA의 대부분의 기능은 엔티티 매니저가 제공한다고 볼 수 있다.

엔티티 매니저는 내부의 데이터베이스 커넥션을 유지하면서 데이터베이스와 통신한다. 따라서 스레드 간에 공유하거나 재사용하면 안 된다. ( 사용하고 버려야 한다. )

import jakarta.persistence.*;

public class JpaMain {

    public static void main(String[] args) {

        //factory는 애플리케이션 로딩 시점에 딱 한번 만들어야 됨.
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); //persistence-unit에서 지정함 이름을 넘긴다.
        EntityManager em = emf.createEntityManager(); //엔티티 매니저 하나 받음 ( 마치 자바 컬렉션이라고 생각 ( 내 객체를 대신 저장해주는 ))
        //code
        EntityTransaction tx = em.getTransaction();		//트랜잭션 API
        tx.begin();	//트랜잭션 시작
        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();		//엔티티 매니저 팩토리 종료
    }
}

비즈니스 로직을 보면 엔티티매니저를 통해서 수행되는 것을 알 수 있다.

 

 

저장

//비즈니스 로직
            Member member = new Member();
            member.setId(2L);
            member.setName("HelloB");
            em.persist(member);

엔티티를 저장하려면, 엔티티 매니저의 persist() 메서드에 저장할 엔티티를 넘겨주면 된다. 위의 코드는 member 엔티티를 생성하고, em.persist(member)를 실행해 엔티티를 저장한다. JPA는 회원 엔티티의 매핑정보를 분석해서 SQL을 만들어 데이터베이스에 전달한다.

INSERT INTO MEMBER (ID, NAME) VALUES ('2L','HelloB')

 

 

수정

 Member findMember = em.find(Member.class, 2L);
 findMember.setName("nameB");

JPA는 어떤 엔티티가 변경되었는지 추적하는 기능을 갖추고 있다. 따라서 member.setName()처럼 엔티티의 값을 변경하면 알아서 UPDATE 쿼리를 작성해서 데이터베이스에 값을 반영한다.

 

 

삭제

em.remove(findMember);

엔티티를 삭제할 때는 엔티티 매니저의 remove() 메서드에 삭제하려는 엔티티를 넘겨주면 된다. 그러면 DELETE 쿼리를 생성해서 실행한다.

 

 

한건 조회

 Member findMember = em.find(Member.class, 2L);

find() 메서드는 조회할 엔티티 타입과, @Id로 데이터베이스 테이블의 기본키와 매핑한 식별자 값으로 엔티티 하나를 조회하는 메서드이다. 이 메서드를 사용하면 SELECT 쿼리를 생성해서 데이터베이스에 결과를 조회한다. 그리고 조회한 값으로 엔티티를 생성해서 반환한다.

 

 

종료

마지막으로 사용이 끝난 엔티티 매니저는 꼭 종료해주어야 한다.

그리고 그다음으로 애플리케이션을 종료할 때 엔티티 매니저 팩토리도 다음처럼 종료해야 한다.

em.close();
emf.close();

 

정리

엔티티 매니저 팩토리의 특징

* 엔티티 매니저를 만드는 역할을 수행한다.
* 생성 비용이 크다
* 하나의 프로젝트 내에서 한개만 만들어서 사용한다. ( 하나의 어플리케이션에서 하나 생성 후 공유 )
* 여러 스레드가 동시에 접근해도 안전하게 설계

엔티티 매니저의 특징

* 생성 비용이 적다.
* 여러 스레드가 동시에 접근하면 동시성 문제가 발생한다. -> 엔티티 매니저 팩토리와는 달리 공유하지 않는다.
* DB 커넥션 풀에서 연결이 꼭 필요한 시점에 커넥션을 얻어서 사용한다. ( 사용자 요청에 의해 트랜잭션을 시작할 때 )

 

 

 

Reference

[1] 인프런 김영한 님의 강의 - https://www.inflearn.com/course/ORM-JPA-Basic/dashboard

 

자바 ORM 표준 JPA 프로그래밍 - 기본편 | 김영한 - 인프런

김영한 | JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다., 실무에서도

www.inflearn.com

[2] 김영한 - 자바 ORM 표준 JPA 프로그래밍

[3] https://jays-lab.tistory.com/35 

 

JPA 엔티티 매니저 팩토리와 엔티티 매니저, 영속성 컨텍스트

엔티티 매니저 팩토리와 엔티티 매니저 엔티티 매니저는 엔티티를 저장, 수정, 삭제, 조회등 엔티티와 관련된 모든 일을 처리. 엔티티 매니저 팩토리를 생성하는 코드. EntityManagerFactory emf = Persist

jays-lab.tistory.com

[4] https://psvm.kr/posts/tutorials/jpa/2-start-jpa-with-gradle

 

JPA 프로젝트 Gradle로 시작하기

IntelliJ 커뮤니티 버전을 사용해 JPA 5 버전 프로젝트를 Gradle로 설정하자.

psvm.kr

 

'JPA' 카테고리의 다른 글

[JPA] 영속성 관리, 영속성 컨텍스트  (0) 2024.05.03
[JPA] 데이터베이스 방언, Dialect  (0) 2024.05.03

JPA는 특정 데이터베이스에 종속적이지 않은 기술이다. 따라서 다른 데이터베이스로 손쉽게 교체할 수 있다. 

 

SQL은 표준 SQL인 ANSI SQL이 있으며, ANSI SQL 이외에 각 DBMS Vendor인 MS-SQL, Oracle, MySQL, PostgreSQL에서 자신만의 기능을 추가한 SQL이 있다. ANSI SQL이 모든 DBMS에서 공통적으로 사용가능한 핵심 표준 SQL이지만, 여러 제품의 DBMS에서는 자신만의 독자적인 기능을 위해 추가적인 SQL을 만들었다. 즉,  각 데이터베이스가 제공하는 SQL 문법과 함수가 조금씩 다르다는 문제점이 있다. 예를 들면 다음과 같은 차이점들이 존재한다.

 

  • 데이터 타입 : 가변 문자 타입으로 MySQL은 VARCHAR, 오라클은 VARCHAR2를 사용한다.
  • 다른 함수명 : 문자열을 자르는 함수로 SQL 표준은 SUBSTRING()을 사용하지만 오라클은 SUBSTR()을 사용한다.
  • 페이징 처리 : MySQL은 LINIT를 사용하지만 오라클은 ROWNUM을 사용한다.
  • 기본키 할당 : MySQL은 AUTO_INCREMENT 오라클은 SEQUENCE 를 사용한다.

 

이처럼 SQL 표준을 지키지 않거나 특정 데이터베이스만의 고유한 기능을 JPA에서는 방언(Dialect)라고 한다. 데이터 베이스에 종속되는 기능을 많이 사용하게 되면 나중에 데이터베이스를 교체하기 힘들다. JPA는 직접 SQL을 작성하고 실행하는 형태이기 때문에 별도 Dialect 설정을 해주면 JPA가 DBMS에 맞는 쿼리를 생성한다. 

따라서 JPA가 제공하는 표준 문법에 맞추어 JPA를 사용하면 되고, 특정 데이터베이스에 의존적인 SQL은 데이터베이스 방언이 처리해 준다. 따라서 데이터베이스가 변경되어도 애플리케이션 코드를 변경할 필요 없이 데이터베이스 방언만 교체하면 된다. JPA에서는 Dialect라는 추상화된 방언 클래스를 제공하고, 각 벤더에 맞는 구현체를 제공하고 있기 때문이다.

 

 

JPA에서는 설정에 맞게 Dialect만 설정해주면 해당 Dialect를 참고하여 그에 알맞은 쿼리를 작성해 준다. 따라서 개발 시에 Oracle DB에 맞게 설정하고 애플리케이션을 개발하다가 실제 고객의 환경이 SQL SERVER를 사용 중이라면 설정만 SQLServerDialect로 변경해 줌으로써 불필요한 변경에 대한 자원 소모를 줄일 수 있다.

 

 

하이버네이트 Dialect 설정과 종류

- Maven ( META-INF/persistence.xml)

프로젝트를 Maven으로 설정할 경우, Maven에서 설장 파일 기본 템플릿은 다음과 같다.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/persistence">
    <persistence-unit name="이름">
        <properties>
        
        
        
        
        </properties>
    </persistence-unit>

</persistence>

 

설정파일인 persistence.xml의 hibernate.dialect 설정값만 바꾸어 주면 된다. 

  <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>

이 부분이 Dialect 를 설정해준 부분인데 데이터베이스 dialect를 H2로 설정한 것이다.  이밖에도 JPA를 사용할 때 필수적으로 설정해야 하는 정보는 다음과 같다. ( H2 데이터베이스 사용한다고 가정. )

            <!-- 필수 속성 -->
            <!--데이터베이스 접근 정보-->
            <property name="jakarta.persistence.jdbc.driver" value="org.h2.Driver"/>
            <property name="jakarta.persistence.jdbc.user" value="sa"/>
            <property name="jakarta.persistence.jdbc.password" value=""/>
            <property name="jakarta.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>

그리고 만약, H2가 아니라, 다른 DB를 사용한다면, 아래와 같이 속성값을 변경하면 된다.

  • H2 : org.hibernate.dialect.H2Dialect
  • Oracle 10g : org.hibernate.dialect.Oracle10gDialect
  • MySQL : org.hibernate.dialect.MySQL5InnoDBDialect

 

하이버네이트의 경우 설정 파일인 persistence.xml의 설정값을 다음과 같이 설정했다.

H2 데이터베이스를 사용했기 때문에 다음과 같이 hibernate.dialect 속성을 org.hibernate.dialect.H2 Dialect로 설정했다

<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />

 

 

Hibernate 전용 속성

참고로, 하이버네이트를 사용할 경우, 다음과 같은 속성들이 존재한다.

hibernate.show_sql : 하이버네이트가 실행한 SQL을 출력

hibernate.format_sql : 하이버네이트가 실행한 SQL을 출력할 때 보기 쉽게 정렬

hibernate.use_sql_comments : 쿼리를 출력할때 주석도 함께 출력

hibernate.id.new_generator_mappings : JPA 표준에 맞춘 새로운 키 생성 전략을 사용

 	<!-- 옵션 -->
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.format_sql" value="true"/>
            <property name="hibernate.use_sql_comments"  value="true"/>
            <property name="hibernate.hbm2ddl.auto" value="create" />

 

-Gradle ( application.properties )

gradle을 사용한다면 JPA 방언 설정은 주로 프로퍼티 파일이나 설정 클래스를 통해서 할 수 있다. ( application.yml, application.properties 파일 )

gradle 프로젝트에서 src/main/resources 디렉토리 하위에 application.properties 파일을 생성하고,

다음과 같이 spring.jpa.properties.hibernate.dialect 를 설정할 수 있다.

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect

만약 application.yml 파일을 사용한다면 다음과 같이 설정할 수 있다.

spring:
  jpa:
    properties:
      hibernate:
        dialect: org.hibernate.dialect.H2Dialect

 

 

dialect 예시

 

Dialect는 보통 데이터베이스 이름 + 버전으로 이루어져 있다

H2 : org.hibernate.dialect.H2Dialect.

오라클 10g : org.hibernate.dialect.Oracle10gDialect.

MySQL : org.hibernate.dialect.MySQL55Dialect // 5.5 버전
MySQL : org.hibernate.dialect.MySQL57Dialect //5.7 버전

 

 

 

 

Reference

[1] https://055055.tistory.com/83 

 

JPA Dialect

김영한님의 강의 내용 정리, oracle dialect 상속 및 사용자 함수 추가 Dialect? 표준 SQL인 ANSI SQL외에, DBMS인 Oracle, MySQL, MS-SQL, PostgreSQL마다 문법과 함수가 조금씩 다른 경우가 있다. 이러한 SQL 표준을

055055.tistory.com

[2] https://dololak.tistory.com/465

 

[JPA - Hibernate] Dialect(방언)이란? 하이버네이트 Dialect 종류

Dialect(방언)이란? 표준 ANSI SQL과 방언 SQL SQL은 다음과 같이 표준 SQL인 ANSI SQL이 있으며, ANSI SQL 이외에 각 DBMS Vendor(벤더, 공급업체)인 MS-SQL, Oracle, MySQL, PostgreSQL 에서 자신만의 기능을 추가한 SQL이

dololak.tistory.com

[3]https://www.inflearn.com/questions/1026626/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EB%B0%A9%EC%96%B8-%EC%84%A4%EC%A0%95

 

데이터베이스 방언 설정 - 인프런

[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]자바 ORM 표준 JPA 프로

www.inflearn.com

[4] https://velog.io/@security-won/JPA-Dialect-DB-%EB%B0%A9%EC%96%B8-%EC%84%A4%EC%A0%95 

 

JPA Dialect, DB 방언 설정

JPA는 특정 데이터베이스에 종속되어있지 않다. 그ㄹ래서 DB를 MySQL을 사용하다가 Oracle로 변경을 해도 문제가 없어야한다. 그렇게 때문에 JPA를 사용할때 사용할 DB의 방언으로 설정을 해줘야한다.

velog.io

[5] 인프런 김영한 님의 강의 - https://www.inflearn.com/course/ORM-JPA-Basic/dashboard 

'JPA' 카테고리의 다른 글

[JPA] 영속성 관리, 영속성 컨텍스트  (0) 2024.05.03
[JPA] Entity와 EntityManager, EntityManagerFactory  (0) 2024.05.03

 

일단 글을 작성하기 앞서, 필자는 컴퓨터공학 계열 학생이며, 3학년 2학기 까지의 과정을 마친 후 4학년 1학기 등록금을 납부 후 휴학을 한 상태이다. 

그런데 휴학 증명서를 뽑아 보니, 3학년으로 찍혀있었고.. 학교 측과 큐넷에 문의해보니 학력변동 확인서를 작성후 교무처장 직인을 받으면 된다는 답을 얻게 되었다!

 

 

정보처리 기사 응시자격 서류 준비

실기를 접수하기 전에 응시자격 서류 제출은 필수이다. 만약 이 기간에 서류를 제출하지 않으면, 필기시험을 봤던것도 무효이며 실기를 접수할 수 없게 된다.

현재 나는 4학년 등록을 한 후 휴학을 신청했지만, 휴학증명서에 3학년이라고 찍혀있었다. 

블로그에 찾아보니 다들 4학년 등록 후 휴학을 하면, 4학년이라 찍히기 때문에 정처기를 볼 수 있다 라고 했었기에.. 나도 등록 후에 휴학을 한건데 학교마다 다른가 보다ㅜㅠ

 

 

하여튼 학력변동 사항 확인서에 내 인적사항(이름, 생년월일, 학과) 과 1번 학적 란에 4학년, 휴학이라고 작성후 학교 학사지원팀에 방문해 교학처장 직인을 받았다. 그리고 첨부 서류로는 휴학 증명서를 준비했다. 이렇게 하면 휴학증명서에는 3학년이라 찍혀있지만, 3학년 수료후 현재 학년이 4학년인 상태에서 휴학을 했다. 라는 것을 증명할 수 있다. 

참고로 학력 변동 사항 확인서는 큐넷 자료실에서 받을 수 있다.

 

 

각종서식 자료실 상세 | Q-net

BODY { FONT-SIZE: 10pt; FONT-FAMILY: Malgun Gothic; COLOR: #000000; MARGIN: 0px } P { MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px; LINE-HEIGHT: 1.2 } LI { MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px; LINE-HEIGHT: 1.2 } 전과, 학과명칭변경, 학년승급, 복수전

www.q-net.or.kr

 

 

서류 제출 방법

큐넷이랑 제휴를 맺은 대학교는 바로 큐넷에서 쉽게 온라인 접수를 할 수 있다. 나도 원래 4학년 재학생이였다면, 바로 온라인 접수를 할 수 있었겠지만

나는 학력변동사항 확인서랑, 휴학증명서를 같이 제출해야 했기에 ( 혹시 몰라 온라인 접수를 시도해 봤으나.. 온라인 접수로는 휴학증명서에 역시나 3학년으로 찍혀 있었다. ) 방문제출 이나, 등기우편 제출만 가능한 상황이였다.

따라서 나는 방문 제출을 택하였고 집에서 그나마 가까운 한국산업인력공단 남부지사에 방문해 제출을 했다.

 

 

 

가서 응시자격 서류심사 접수 신청서를 작성하고, 미리 준비했던 학력변동 확인서랑 휴학증명서를 제출했다.

그랬더니 바로 시험 응시 가능한 상태가 되었다고 말씀해주셨다! 

 

 

4학년 재학생이였다면 바로 집에서 쉽게 접수할 수 있었을텐데 서류때문에 학교도 가고 산업인력공단도 직접 방문해야 되서 너무 번거로웠다..

그래도 이제 서류 접수는 끝났으니 실기 준비만 잘해서 보면 된다! 화이팅 해야지^-^

2024년 3월 4일에 시행한 정보처리기사 1회 필기 시험을 보고 왔다 !

떨어지면... 올해 계획한 일정들이 전부 꼬여버리기 때문에 꼭 붙어야 된다는 생각을 가지고 준비했다.

한번도 자격증 시험을 본 적이 없었고 실기도 같이 준비하자 라는 마인드로 기간을 길게 잡고 공부했다.

 

그리고 필기 접수를 할 당시에 사전 정보 입력도 하고, 시간 딱 맞춰서 1시에 들어가서 시험장 찾기를 시도했으나.. 내가 살고 있는 지역에는 시험장이 없었다^^ 그 와중에 그나마 가까운 시험장은 이미 다 찬 상태이고.. 그래서 하다하다 결국 이태원 역에 있는 한국폴리텍대학에서 시험을 치게 되었다ㅜㅠ.. ( 참고로 아침에 차 밀릴까봐 6시 반에 집에서 나와서 시험장으로 갔다.. )

 

그래서 시험 난이도는 어땠는가 하면

내 기준으로 쉬웠다

누구는 기출 문제에서 많이 안나왔다, 어려웠다는 후기글을 시험 전날 블로그에서 봐서 좀 덜덜 떨면서 시험장에 갔다.

 

그러나 덜덜 떨었던게 민망할정도로 실제 시험에는 기출문제도 꽤 많이 나왔었다. 변형된 문제랑 새로보는 문제들도 있었는데 개념을 여러번 돌려서 그런지 어렵지 않은  문제들이였다. 4과목을 제외하고 문제도 바로바로 풀려서 30분 만에 풀고 나왔다.  그런데 cbt 형식이라 문제가 랜덤하게 나와 사람마다 체감 난이도가 다른것 같다는 생각이 들었다. 

 

cbt 시험은 시험 보고 제출 버튼을 누르면 바로 점수와 합불 여부가 나오기 때문에 버튼을 누르는게 무서웠다. 가채점 결과는 잘 기억이 나지 않지만, 제일 못본 과목은 역시나 2과목 70점 이였고 제일 잘 본 과목은 3과목 95점? 이였던 것 같다. 그리고 최종 평균은 80점이 나왔다.

 

 

나의 상황, 정처기를 준비하게 된 이유

 

 

일단 필자는 컴퓨터공학과 전공자 이며, 3학년 과정까지 마치고 4학년에 휴학을 한 사람이다.  따라서 소프트웨어 공학, 데이터베이스, 프로그래밍 언어 등에 대해 학교에서 공부를 수강했었고 바로 직전학기에는 디자인 패턴 수업을 들으며.. 매주 지옥같던 퀴즈와 시험을 준비했었다.

수업을 들을 때마다 ?나름? 열심히 공부를 했었고 성적 장학금도 여러번 받았기에... 비전공자와 비교한다면 솔직하게 어느 정도 기초 지식이 있는 편이다. 

 

 

그리고 나는 공부도 하고 자격증을 따며 취업 준비를 하기로 결심하고 1년 휴학을 선택했다.

컴공은 자격증이 필요 없다 이런 말들이 많았지만 컴퓨터공학 전공자라면 다들 기본으로 가지고 있는 자격증인 것 같아 준비하게 되었다.

그리고 3년 내내 학교 다니면서 개강-> 시험 -> 과제 -> 프로젝트  과정을 반복하다가 휴학을 해버리니.. 시간도 많이 널널했고 시험 기간이라는 것도 없어지다 보니 사람이 늘어지는 거 같았다. 그래서 스스로에게 긴장감을 주기 위해 시험을 보게 된 것도 있다.

 

 

 

시험 준비 기간, 공부 방법

 

 

 

다들 취준 하면 자격증 따는데 시간 들이지 말고 그 시간에 프로젝트 경험 쌓아라, 코딩 공부해라 라는 말이 많았다. 나도 여기에는 동의하는 편이다.

그래서 나는 시험일로부터 2달 전 부터 평일에만 하루 평균 2시간? 정도씩 정처기 준비에 시간을 투자한것 같다. 하다가 집중 잘되는 날은 좀 더하고 집중 안되는 날은 1시간 공부할때도 있었다. 스트레스 받지 않고 쉬엄쉬엄 했다. 따라서 총 공부시간이라고 하면 많아야 100시간..? 정도 인 것 같다. 

 

참고로 시험 공부는 2024 시나공 정보처리기사 필기 기본서 를 이용해서 공부를 했으며, cbt 기출 문제집 사이트를 이용해서 기출 문제를 많이 풀었던 것 같다.

 

 

 

최강 자격증 기출문제 전자문제집 CBT

전자문제집, CBT, 컴씨비티, 씨비티, 기사, 산업기사, 기능사, 컴활, 컴퓨터활용능력, 1급, 2급, 워드, 정보처리, 전기, 소방, 기계, 사무자동화, 정보기기, 제과, 제빵, 한국사, 공무원, 수능, 필기,

www.comcbt.com

 

 

시나공과 수제비 책이 유명한데 시나공은 2021~2023기출 문제집도 수록되어 있고 잘 나오는 파트별로 A등급, B등급으로 보기 좋게 분류되어 있어 편했다. 나는 정처기 준비하면서 지금까지 학부에서 배운 내용들을 정리하고 싶었기 때문에 이론 부분이 보기 좋게 잘 정리되어 있는 시나공 책을 선택했던 것 같다. 

 

 

시나공 문제집을 구입하고 한달 동안은 기출 문제를 바로 풀기보다는 이론을 정독하고 정독했다. 시험에 합격하기 위해 무작정 외우는 것보다는 이해한다는 것을 목표로 두고 이론을 여러번 정독했던 것 같다. ( 사실 이런 방식 때문에 중간에 좀 늘어졌는 것 같긴하다.. )

 

그리고 나머지 한달 동안은 시나공 기출문제집과 cbt  기출 문제집 사이트에 들어가서 문제를 풀었고, 틀린 부분 위주로 개념을 다시 정리하는 식으로 시간을 보냈다. 이 기간 동안 기출 문제는 단순히 한번만 풀고 넘어가는게 아니라, 셀 수 없이 여러번 풀었다. 

 

따로 시험 전날까지 내용을 따로 정리해두거나 그러지는 않았다. 어차피 필기는 전부 객관식 문제이기도 하고.. 2달이라는 시간동안 내용을 여러번 읽으면서 눈에 어느정도 익혀뒀기 때문에.. 시험 전날에는 그냥 생성 패턴이 아닌것, 등 이런식으로 머리에 가장 안들어오는데 시험때 틀리면 아까울 법한 내용들만 좀 외우다가 잔것 같다. ( 실기를 공부하고 있는 지금은.. 노션에 내용을 정리하면서 공부하고 있는 중이다^^.. )

 

 

후기

 

 

기출 문제를 풀었을때도 평균 70에서 90 정도로 나왔었는데 실제 시험도 평균 80이 나왔다. 기간을 넓게 잡고 문제집을 정독하다 보니 새로운 문제가 나와도 당황하지 않았던 것 같다.

누가 기사 필기 시험을 2달이나 잡고 하냐 라고 말할 수도 있는데 2달동안 내용을 나눠서 조금씩 여러번 공부하는 방식으로 하다보니 그래도 공부하는 과정이 고통스럽지 않았다..! 그리고 실기를 준비하는 지금에서야 말할 수 있는 것이지만, 그때 그렇게 했기 때문에 실기 공부하는게 덜 힘든 것 같다.

 

그리고 확실히 4과목에서 프로그래밍 문제의 비중이 많아진 것 같다는 걸 느꼈다. 제대로 세어보지는 않았지만, 거의 절반 이상이 프로그래밍 문제 였던 것 같다. c 언어 포인터와 배열, 구조체, 자바 클래스 간의 상속 ( 메소드 오버라이딩 ) 에 대해 묻는 문제가 많이 나왔다. 코딩 문제는 기출문제에서 본 문제는 2개..? 정도였고 나머지는 전부 새로 보는 문제였다. 그래서 나눠주신 연습장에다가 손으로 작성해가며 문제를 푸느라 시간이 제일 오래 걸렸다. 포인터에 대한 이해도가 낮았다면 4과목도 분명 많이 틀렸을 것이다. 다행히도 서브네팅에 대한 지식은 부족했는데 여기서는 1문제 나와서 그냥 찍었다^^

 

그리고 다른 과목에서도 기출문제가 있긴 했지만 새로 보는 문제들도 꽤 있었다. .. 그래서 시험을 준비한다면 단순하게 기출 문제만 달달 풀기만 한다면 아슬아슬하게 합격할 것 같다는 생각이 들었다. 확실하게 합격을 원한다면 이론을 좀 더 정독하는 것을 추천하고 싶다.

 

동회차 필기 실기 합격이 어렵다고 하는데 실기도 한번에 합격하길 기원하며..! 이 글을 보는 누군가도 정처기 필기 한번에 합격을 기원합니다🥺

'자격증' 카테고리의 다른 글

정보처리 기사 응시자격 서류, 4학년 휴학생  (0) 2024.03.19

 

 

1934번: 최소공배수

두 자연수 A와 B에 대해서, A의 배수이면서 B의 배수인 자연수를 A와 B의 공배수라고 한다. 이런 공배수 중에서 가장 작은 수를 최소공배수라고 한다. 예를 들어, 6과 15의 공배수는 30, 60, 90등이 있

www.acmicpc.net

 

단순하게 최소 공배수를 구하는 문제이다.

이 문제에서 포인트는 최소 공배수는 A와 B 가 주어졌을 때  "A*B / 최대공약수" 를 계산해 구할 수 있다. 는 것이다.

결국 유클리드 호제법을 이용해서 최대 공약수를 구하면 해결 할 수 있다. 

 

유클리드 호제법에 관해 정리해 둔 글이다.

 

[JAVA] 유클리드 호제법 - 최대 공약수 구하기

최대 공약수를 구하는 방법 일반적으로 최대 공약수를 구하려고 하면 소인수 분해를 이용해서 공통된 소수들의 곱으로 표현한다. 그러나 소인수 분해를 위해 소수를 먼저 찾아야 하고, 찾은 소

hyeondaya.tistory.com

 

 

 

코드는 다음과 같다.

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

public class p1934 {

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int T = Integer.parseInt(br.readLine());
        StringTokenizer st;
        for (int i = 0; i < T; i++) {
            st = new StringTokenizer(br.readLine());
            int A = Integer.parseInt(st.nextToken());
            int B = Integer.parseInt(st.nextToken());
            int result = A * B / gcd(A, B);
            System.out.println(result);
        }

    }
    private static int gcd(int A, int B ){
        if(B==0) return A;
        else return gcd(B, A % B);
    }
}

 

 

 

최대 공약수를 구하는 방법

 

일반적으로 최대 공약수를 구하려고 하면 소인수 분해를 이용해서 공통된 소수들의 곱으로 표현한다. 그러나 소인수 분해를 위해 소수를 먼저 찾아야 하고, 찾은 소수가 두개의 수를 공통적으로 나눌 수 있는지 확인해야 하기 때문에 이는 효율적이지 않다.  유클리드 호제법을 이용하면 더 간단한 방법으로 최대 공약수를 구할 수 있다.

 

 

유클리드 호제법(Euclidean Algorithm)

 

두 개의 자연수(두 개의 다항식)의 최대 공약수를 구하는 알고리즘이다. 

호제법이란 말은 두 수가 서로 상대방 수를 나누어 결국 원사는 후를 얻는 알고리즘을 나타낸다.   

 

 

2개의 자연수(또는 정식) a,b에 대해서 a를 b로 나눈 나머지를 r이라고 하면( 단, a>b )  a와 b의 최대 공약수는 b 와 r의 최대공약수와 같다. 이 성질에 따라 b를 r로 나눈 나머지 r' 를 구하고, 다시 r을 r'로 나눈 나머지를 구하는 과정을 반복하여 나머지가 0이 되었을때 나누는 수가 a 와 b 의 최대 공약수가 되는 것이다.

 

 

MOD 연산

 

유클리드 호제법을 수행하려면, MOD 연산을 이해하고 있어야 한다. MOD 연산이 최대 공약수를 구하는데 사용하는 핵심 연산이기 때문이다.  MOD 연산은 다음과 같다.

 

연산 기능 예제
MOD 두 값을 나눈 나머지를 구하는 연산 10 MOD 4 = 2 //10%4=2

 

MOD 연산은 다시 말해 두 값을 나눈 나머지를 구하는 연산이라 볼 수 있다. MOD 연산을 이용하면 유클리드 호제법을 구현할 수 있다.

 

 

1. 먼저 큰 수를 작은수로 나눈 나머지를 구한다. ( MOD 연산 )

270 MOD 192 = 78

//270 % 192 = 78 과 같다. ( 큰 수에서 작은수로 MOD 연산을 진행 )

2. 앞 단계에서 작은 수와 MOD 연산 결과값( 나머지 )으로  또 MOD 연산을 수행한다.

192 MOD 78 = 36 //192 % 78 =36

3. 위 과정을 반복해서 나머지가 0이 되면, 그 순간의 나누는 수를 최대 공약수로 선택한다.

78 MOD 36 = 6
36 MODE 6 = 0

//따라서 gcd(270,192) = 6

 

 

 

따라서 정리하자면

  • 유클리드 호제법은 나눗셈만을 반복해서 최대공약수(GCD)를 구할 수 있다.
  • 두 개의 수가 아무리 커도 정해진 순서로 계산하면 효율적으로 최대공약수를 구할 수 있다

 

이를 코드로 나타내면 다음과 같다.

    private int gcd(int a, int b) {
        if(b==0) return a;
        else return gcd(b, a % b);
    }

 

 

관련된 문제들 ( 발견하면 계속해서 추가 )

백준1934_ 최소공배수  (https://www.acmicpc.net/problem/1934)

백준1850_ 최대공약수 (https://www.acmicpc.net/problem/1850)

백준1033_ 칵테일 (https://www.acmicpc.net/problem/1033)

 

Referance

 

 

유클리드 호제법 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 유클리드 호제법(-互除法, Euclidean algorithm) 또는 유클리드 알고리즘은 2개의 자연수 또는 정식(整式)의 최대공약수를 구하는 알고리즘의 하나이다. 호제법이란

ko.wikipedia.org

 

 

유클리드 호제법(Euclidean algorithm)

‣ 유클리드 호제법 유클리드에 의해 기원전 300년경에 발견된 가장 오래된 알고리즘으로, 두 수의 최대공약수를 구하는 알고리즘이다. 두 수가 서로 상대방 수를 나누어서 결국 원하는 수를 얻

parade621.tistory.com

 

'알고리즘' 카테고리의 다른 글

[JAVA] 에라토스테네스의 체 - 소수 구하기  (0) 2024.02.15

https://school.programmers.co.kr/learn/courses/30/lessons/12977 

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

문제를 단순하게 정리하자면, 주어진 문제는 배열에 있는 숫자들 중에 3개를 골라 더했을때 소수가 되는 경우의 개수를 구하면 되는 문제이다. 

 

처음에 딱 보고 든 생각은 다음과 같다. 

 

3개의 수는 어떻게 뽑을 것인가..?

 

방법 1. ) 사실 단순한 방법은 for문을 3번 돌리면서 값을 구한뒤 , 그 값이 소수인지를 판별하는 것이다. 

방법 2. ) 배열의 조합 값들을 모두 찾아내서 정리한뒤 ( 재귀나 백트래킹 이용 ) 조합의 합이 소수인지를 판별하는 것이다.

그래서 일단 두가지 방법을 모두 구현해보고자 했다.

 

방법 1. - for문을 3번 돌리면서 값을 구하고 그 값을 소수 판별하기

class Solution {
   public int solution(int[] nums) {
        int answer = 0;
        for (int i = 0; i < nums.length; i++) {
            for (int j = i+1; j < nums.length; j++) {
                for (int k = j + 1; k < nums.length; k++) {
                    int target = nums[i] + nums[j] + nums[k];
                    if(isPrime(target)) answer++;
                }

            }
        }
        return answer;
    }
    private boolean isPrime(int target) {
        for (int i = 2; i <= Math.sqrt(target); i++) {
            if (target % i == 0) {
                return false;
            }
        }
        return true;
    }
}

코드만 봐도 그렇게 어렵지 않다. 

 

방법 2. 백트래킹을 이용해서 만들수 있는 조합 리스트를 만든뒤, 해당 조합의 합이 소수를 만족하는지 판별하기

 

import java.util.ArrayList;

class Solution {
      static ArrayList<Integer> list;
    public int solution(int[] nums) {
        boolean[] visited = new boolean[nums.length];
        list = new ArrayList<>();
        comb(nums, visited, 0, nums.length, 3 );
        return list.size();
    }
    void comb(int[] arr, boolean[] visited, int start, int n, int r) {
        if (r == 0) {
            print(arr, visited, n);
            return;
        }
        for (int i = start; i < n; i++ ) {
            visited[i] = true;
            comb(arr, visited, i + 1, n, r - 1);
            visited[i] = false;
        }
    }

    void print(int[] arr, boolean[] visited, int n) {
        int target =0;
        for (int i = 0; i < n; i++) {
            if (visited[i]) {
                target += arr[i];
            }

        }
        if (isPrime(target)) {
            list.add(target);
        }
    }
    private boolean isPrime(int target) {
        for (int i = 2; i <= Math.sqrt(target); i++) {
            if (target % i == 0) {
                return false;
            }
        }
        return true;
    }

}