- Published on
- •👁️
5월9일 기술 공부 - 기타
- Authors

- Name
- River
allocationSize로 성능 최적화가 가능해 Oracle, PostgreSQL 등에서 쓰입니다. TABLE은 JPA가 별도 테이블을 생성해 ID를 관리하는 방식인데, select 후 update 쿼리가 추가로 발생해 성능이 떨어지고 실무에서는 거의 사용되지 않습니다. AUTO는 JPA가 사용하는 DB 방언에 따라 ID 전략을 자동 선택하는 방식입니다.상세 설명
JPA에서 ID 생성 전략
- JPA에서 ID 생성 전략은 엔티티의 PK를 자동으로 생성하는 방법을 말하며, 생성 전략은 AUTO, IDENTITY, SEQUENCE, TABLE이 있다.
- 이 때 엔티티의 필드에
@GeneratedValue애노테이션과 함께 적용할 생성 전략을 지정
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
IDENTITY
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
엔티티를 DB에 insert 하게 되면 DB의 auto-increment 기능으로 ID가 생성되고 이 값을 받아오는 전략
이 때문에 flush 시점에 ID가 결정된다.
MySQL에서 자주 사용된다. MySQL의 경우 데이터베이스 시퀀스 기능이 존재하지 않기 때문이다.
IDENTITY 전략은 영속성 컨텍스트에 저장 시점에 즉시 INSERT 쿼리가 실행되어 ID를 얻어온다.
일반적인 트랜잭션 쓰기 지연이 동작하지 않는 예외 케이스
SEQUENCE
@Id @SequenceGenerator(name = "seq_gen", sequenceName = "my_seq", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_gen") private Long id;
데이터베이스의 시퀀스 객체를 통해 ID를 사전에 생성한다.
엔티티를 insert 하기 전에 시퀀스를 조회하여 ID를 가져오고 이 ID와 함께 insert 쿼리를 날린다.
IDENTITY 방식에 비해 성능상 유리하다. (DB 자체 기능으로 매우 빠름)
allocationSize로 미리 ID를 가지고 올 수 있어 성능 최적화가 가능하다.Oracle, PostgreSQL의 경우 시퀀스 기능이 존재하기 때문에 주로 이러한 DB에서 사용된다.
allocationSize(기본값 50)를 설정하면 시퀀스를 한 번에 여러 개 가져와 메모리에서 사용.
이는 빈번한 DB 접근을 줄여 성능을 향상시킨다.
AUTO
@Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id;
JPA가 사용하는 DB의 Dialect에 따라 자동으로 전략을 선택
MySQL →
IDENTITY, Oracle →SEQUENCE
TABLE
@Id @TableGenerator(name = "table_gen", table = "id_generator", pkColumnValue = "order_id")
@GeneratedValue(strategy = GenerationType.TABLE, generator = "table_gen") private Long id;
JPA가 자체적으로 DB에 시퀀스용 테이블을 만들어 ID를 관리
DB에 독립적이지만, 시퀀스 조회를 위한 추가 쿼리가 발생해 성능이 떨어진다.
현재까지의 ID를 select, 이후 새로운 ID를 위해 update 해야 한다.
실무에서 거의 사용되지 않는다.
TABLE 전략은 모든 데이터베이스에서 사용 가능하다는 장점이 있지만, 성능 이슈로 인해 실무에서는 권장되지 않는다. ID 생성을 위해 별도의 테이블 락이 발생할 수 있다.
상세 설명
로그 (Log)
- 사람이 읽을 수 있는 텍스트 형식의 애플리케이션 동작 이력(이벤트)을 순서대로 기록한 것
- 로그 레벨은 trace, debug, info, warn, error, fatal로 중요도를 구분할 수 있다.
- 문제 추적(에러 메시지, stack trace)과 디버깅에 강력한 도구
메트릭 (Metric)
- 시스템이나 애플리케이션의 상태를 정수 또는 실수 형태의 수치 데이터로 나타내는 지표
- CPU 사용률, 메모리 사용량, 요청 처리 시간, TPS 등
- 사람보다 시스템이 읽고 분석하기에 적합
- 실시간 모니터링, 시각화 및 알람 설정에 유리하다.
- 시계열 데이터로 저장된다. (Prometheus, Graphite 등)
상세 설명
얕은 복사와 깊은 복사는 객체를 복사하는 2가지 방법이다.
얕은 복사 (Shallow Copy)
- 객체의 최상위 레벨 속성만 복사, 아래 레벨 객체의 참조는 그대로 유지된다.
- 즉, 객체를 복사할 때 객체 자체는 새로 만들지만, 내부 객체는 원본 객체와 공유한다.
- Ex. 리스트를 얕은 복사하면 리스트 객체 자체는 새로 생성되지만, 내부 요소들은 원본 리스트와 동일한 객체를 참조한다
깊은 복사 (Deep Copy)
- 객체의 하위 모든 레벨을 재귀적으로 복사하여 모두 복제한다. 즉, 원본 객체와 완전히 독립된다.
- 얕은 복사에 비해 느리지만, 얕은 복사의 경우 공유하는 내부 객체가 변경될 수 있기 때문에 독립적으로 사용하고자 하는 경우 깊은 복사를 해야 한다.
- Ex. 리스트를 깊은 복사하면 리스트 객체 뿐만 아니라, 내부 객체들 모두 새롭게 만든다.
상세 설명
트랜잭션 격리 수준(Isolation Level)이란?
- 동시에 실행되는 트랜잭션 간의 간섭 허용 범위를 정의
- 3가지 동시성 문제를 어떻게 제어할지 정한 표준 규칙이다.
- SQL 표준 격리 수준은 Read Uncommitted, Read Committed, Repeatable Read, Serializalbe으로 4단계가 존재한다.
| 격리 수준 | Dirty Read | Non-repeatable Read | Phantom Read |
|---|---|---|---|
| READ UNCOMMITTED | O | O | O |
| READ COMMITTED | X | O | O |
| REPEATABLE READ | X | X | O |
| SERIALIZABLE | X | X | X |
- 대부분의 DBMS는 Read Committed이거나, Repeatable Read를 사용한다.
- MySQL : Repeatable Read
- Oracle, PostgreSQL : Read Committed
- 정합성이 매우 중요한 경우만 Serializable을 고려한다.
- MySQL은 기본적으로 Repeatable Read 수준을 사용하지만, MVCC를 통해 실제로는 Phantom Read도 방지한다
대표적인 동시성 문제
- Dirty Read
- 커밋되지 않은 데이터를 읽음
- Non-repeatable Read
- 같은 쿼리를 두 번 했는데 결과(Row)가 다르다.
- 다른 트랜잭션에서 update를 하는 경우
- Phantom Read
- 같은 조건의 쿼리인데 결과 row의 수가 다르다.
- 다른 트랜잭션에서 insert, delete를 하는 경우
상세 설명
일급 컬렉션 (First-Class Collection)
일급 컬렉션은 컬렉션을 감싸는 클래스로, 컬렉션을 직접 사용하지 않고 컬렉션 관련 로직을 클래스로 캡슐화하는 설계 패턴이다.
객체 지향 설계나 DDD 방식을 따르는 방법으로 이를 통해 컬렉션 구조의 불변성을 유지하고 컬렉션을 조작하는 것을 일급 컬렉션을 통해 수행하여 유지보수성을 높일 수 있고, SOLID의 SRP에 맞는 설계이고 응집도 높은 설계 패턴이다.
일급 컬렉션은 컬렉션만을 내부 필드로 가지고, 컬렉션을 생성자를 통해 받는다. 다만, 이 때 원본 컬렉션 객체의 주소를 받지 않고, 얕은 복사를 통해 복사한 객체를 받아서 컬렉션 구조의 불변성을 보장한다.
단, 얕은 복사이므로 컬렉션 객체 내부 객체의 불변성은 보장되지 않는다.
Ex.
List<Post>를 대신Posts라는 클래스를 만들고 클래스 내부 메서드를 통해 List를 관리한다.