import jakarta.persistence.*;
import java.time.LocalDateTime;
public class AuditListener {
@PrePersist
public void perPersist(Object o) {
if (o instanceof Auditable) {
((Auditable) o).setCreateAt(LocalDateTime.now());
((Auditable) o).setUpdateAt(LocalDateTime.now());
}
}
@PreUpdate
public void perUpdate(Object o) {
if (o instanceof Auditable) {
((Auditable) o).setUpdateAt(LocalDateTime.now());
}
}
}
import jakarta.persistence.*;
import java.time.LocalDateTime;
@Entity
@NoArgsConstructor
@Data
@EntityListeners(AuditListener.class)
public class Post implements Auditable {
@Id
@GeneratedValue
private Long id;
private String title;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
// getter/setter 생략 가능
}
AuditingEntityListener
Spring Boot에서 제공하는 AuditingEntityListener는 Spring Data JPA의 감사(Auditing) 기능을 자동화해주는 리스너 클래스다. 이 리스너를 통해 createdDate, lastModifiedDate, createdBy, lastModifiedBy 같은 필드를 자동으로 관리할 수 있다.
ORM은 Object Relational Mapping의 약자로, 객체 지향 프로그래밍 언어(예: Java)에서 사용하는 객체(엔티티)와 관계형 데이터베이스(RDB)에서 사용하는 테이블 간의 불일치를 해결하고, 이 둘을 자동으로 매핑해주는 기술입니다. 즉, 자바의 객체와 데이터베이스의 테이블을 1:1로 연결해주는 중계자 역할을 하며, 개발자가 객체를 조작하면 그에 맞춰 자동으로 데이터베이스에 반영되도록 해줍니다
@GeneratedValue는 JPA(Java Persistence API)에서 엔티티 클래스의 주요 키(Primary Key) 값을 자동으로 생성하기 위해 사용하는 어노테이션입니다. 주로 @Id와 함께 사용되어, 데이터베이스에 엔티티를 저장할 때 해당 필드의 값을 자동으로 생성하도록 지시합니다
JpaRepository<{Entity 클래스} , {PK 데이터 타입}> 을 상속 받는다.
Application.yml 설정
spring:
jpa:
show-sql: true #jpa 사용 시 sql 로그 출력
properties:
hibernate:
format_sql: true # sql 로그를 sql 포맷형식으로 출력
defer-datasource-initialization: true
h2:
console:
enabled: true
Spring Boot 2.5 이상부터는 기본적으로 data.sql과 같은 SQL 스크립트가 Hibernate(JPA)의 DDL(테이블 생성 등) 작업보다 먼저 실행된다. 이 때문에 Hibernate가 아직 초기화 되지 않았는데 data.sql이 실행되어 에러가 발생할 수 있다.
spring.jpa.defer-datasource-initialization: true를 설정하면 Hibernate의 DDL 작업(엔티티 기반 테이블 생성 등)이 모두 끝난 뒤에 data.sql, schema.sql 등 SQL 스크립트가 실행된다
JPA 주요 메소드 및 네이밍 규칙 정리
JpaRepository가 기본적으로 제공하는 주요 메소드와 Spring Data JPA 쿼리 메소드 네이밍 규칙을 아래와 같이 정리할 수 있습니다.
// 콘솔 결과
pages :Page 2 of 2 containing com.example.bookmanager.domain.User instances
totalElements :5
totalPages :2
Number of elements :2
sort :UNSORTED
size : 3
QueryByExampleExecutor란?
QueryByExampleExecutor는 Spring Data JPA에서 제공하는 인터페이스로, 엔티티의 일부 필드 값(예: name, email 등)을 예시로 삼아 동적 쿼리(Example Query)를 쉽게 생성할 수 있게 해줍니다. 즉, “이런 값이 들어있는 엔티티를 찾아줘”라는 식의 검색을 코드 몇 줄로 구현할 수 있다.
위 방식은 특히 문자열에 관련된 것만 쓸 수 있다는 한계점이 있어서 조금 복잡한 쿼리를 만들 때는
에라토스테네스의 체는 2부터 N까지의 자연수 중에서 소수를 빠르고 효율적으로 찾는 대표적인 알고리즘입니다. 이 방법은 소수가 아닌 수(합성수)를 체로 걸러내듯이 제거해 나가면서 소수만 남기는 방식입니다.
동작 원리 요약 1. 2부터 N까지 모든 수를 나열 2. 남아있는 수 중 가장 작은 수(i)를 소수로 판정 3. i의 배수(2i, 3i, 4i, ...)를 모두 제거 4. 이를 N의 제곱근까지 반복
이 과정을 거치면 남아있는 수가 모두 소수입니다.
코드 예시
n = 100 # 2부터 100까지 소수 구하기
prime = [True for _ in range(n + 1)] # 소수 여부를 저장하는 리스트
for i in range(2, int(n**0.5) + 1):
if prime[i]:
for j in range(i * 2, n + 1, i): # i의 배수들은 소수가 아님
prime[j] = False
# 소수 출력
for i in range(2, n + 1):
if prime[i]:
print(i, end=' ')
시간 복잡도 O(nloglogn)으로, 매우 효율적
한 번에 여러 소수를 구할 때 특히 빠르다. 특정 범위의 소수 개수, 소수의 합 등 다양한 문제에 응용 가능
문제 서강대학교 컴퓨터공학과 실습실 R912호에는 현재 N개의 창문이 있고 또 N명의 사람이 있다. 1번째 사람은 1의 배수 번째 창문을 열려 있으면 닫고 닫혀 있으면 연다. 2번째 사람은 2의 배수 번째 창문을 열려 있으면 닫고 닫혀 있으면 연다. 이러한 행동을 N번째 사람까지 진행한 후 열려 있는 창문의 개수를 구하라. 단, 처음에 모든 창문은 닫혀 있다.
예를 들어 현재 3개의 창문이 있고 3명의 사람이 있을 때,
1번째 사람은 1의 배수인 1,2,3번 창문을 연다. (1, 1, 1) 2번째 사람은 2의 배수인 2번 창문을 닫는다. (1, 0, 1) 3번째 사람은 3의 배수인 3번 창문을 닫는다. (1, 0, 0) 결과적으로 마지막에 열려 있는 창문의 개수는 1개 이다.
입력 첫 번째 줄에는 창문의 개수와 사람의 수 N(1 ≤ N ≤ 2,100,000,000)이 주어진다.
출력 마지막에 열려 있는 창문의 개수를 출력한다.
예제 입력 1 3 예제 출력 1 1 예제 입력 2 24 예제 출력 2 4
N = int(input())
print(int(N**0.5))
정리
**완전제곱수(perfect square)**란 어떤 정수 k에 대해 k² 형태로 표현되는 수 예: 1 = 1², 4 = 2², 9 = 3², 16 = 4², ..., k² ≤ N
우리가 궁금한 건:
N 이하의 완전제곱수는 총 몇 개인가?
모든 자연수 i (1 ≤ i ≤ k)에 대해 i²를 구했을 때, i² ≤ N을 만족해야 완전제곱수임. 여기서 가장 큰 그런 i는 바로 i = ⌊√N⌋, 즉 int(N**0.5)이다.