Share
Sign In
📚

JPA with Kotlin

자바와의 차이점

자바 기본 entity
@Entity @AllArgsConstructor class Person { @ID long id; @Column String name; @Column int age; }
but, 코틀린
@Entity class Person( @ID var id: Long, @Column var name: String, @Column var age: Int )

Data Class 기본 생성자

Defualt Value 선언

코틀린 공식 문서에서, 모든 필드에 기본값을 생성 → 기본 생성자 생성

부생성자 사용

주 생성자 호출 이후, 부생성자를 사용가능

Final 클래스와 JPA 엔티티

코틀린에서 기본적으로 생성되는 모든 클래스들으니 final이다. final를 통해 상속을 불가능하게 한다.

AOP 적용이 불가능

Spring AOP는 CGLIB 프록시 기반 동작이기에, 상속을 금지, 프록시 생성 불가능, final을 하면 안된다. → 해결법 인터페이스 추가
이유
Spring AOP는 기본적으로 두 가지 방식으로 프록시를 생성합니다:
1.JDK 동적 프록시 (JDK Dynamic Proxy)
•인터페이스를 구현한 클래스만 프록시를 생성합니다.
•클래스 자체에 final이 붙어도 상관없습니다.
(단, 해당 클래스가 인터페이스를 구현해야 함.)
2.CGLIB 프록시 (Code Generation Library)
•클래스 상속을 통해 프록시를 생성합니다.
•final 클래스는 상속이 불가능하므로 CGLIB 프록시를 생성할 수 없습니다.
즉, 클래스에 final이 붙어 있다면 CGLIB 프록시를 사용할 수 없고, 클래스가 인터페이스를 구현하지 않았다면 JDK 동적 프록시도 사용할 수 없게 되어 AOP가 동작하지 않습니다.
@Service @Transactional(readOnly = true ) class LostPostService( )

지연로딩(Lazy Initialization)

기본 JPA 스펙에서 영속성 클래스와 메서드에 final이 붙으면 안된다. → 영속성 컨텍스트의 지연로딩
in JPA, 조희하려는 객체의 연관된 엔티티의 필드값을 나중에 가져오고 싶을 때 불필요한 SQL 조회 쿼리가 나가는 것을 막기 위해 원본 엔티티를 상속받은 프록시 객체를 생성한다.
프록시 객체는 ID만 존재, 필드에 데이터가 업어도 먼저 조회 가능

Spring Plugin

스프링 플러그인은 @Component, @Async, @Transactional, @Cacheable, @SpringBootTest 와 같은 거의 모든 클래스에 자동으로 open 키워드를 추가
하지만 @Entity, @Embeddable 과 같은 JPA와 관련한 어노테이션들은 대상에서 제외되므로, 아래와 같이 build.gradle에 수동으로 추가해주어야 한다.

기본 생성자와 JPA 엔티티

기본값을 설정, 보조 생성자를 제작하지 않는다면 기본 생성자가 존재하지 않음.
하지만 Hibernate(자바 언어를 위한 객체 관계 매핑 프레임워크)는 리플렉션(Reflection)을 통해 엔티티 클래스를 인스턴스화 진행 → 기본 생성자 필요
리플렉션을 통한 객체 생성
fun createNewInstance() { val tempClass: Class<*> = Temp::class.java val constructor: Constructor = tempClass.getConstructor() // 인자가 없는 생성자 // 동적 object 생성 val result: Temp = constructor.newInstance() as Temp }
@Entity 에 대한 기본 생성자
kotlin-jpa 플러그인이 자동으로 생성
orm 이란 object relational mapping 의 약자로 객체와 rdbms (관계형 데이터베이스) 를 맵핑해주는 도구이다.

exposed

경량 ORM:
•JPA와 같은 무겁고 복잡한 ORM보다 단순하게 설계되어 있음.
•SQL Mapper와는 다른 고수준의 API를 제공하면서도, SQL 작성에 유연성을 제공.
2.Entity Cache 지원:
•트랜잭션 단위로 엔티티 캐싱을 지원. (JPA와 유사하지만 구현 방식은 다를 수 있음.)
•캐시를 활용해 중복 데이터 로딩 방지.
3.DSL 지원:
•QueryDSL처럼 DSL 기반으로 직관적인 쿼리 작성을 지원.
•QClass는 QueryDSL처럼 자동 생성되지 않으며, 수동으로 선언하여 사용.
4.DAO 패턴:
•DAO(데이터 접근 객체) 패턴을 지원하며, Lazy와 Eager 로딩 전략 제공.
•기본적으로 Lazy 로딩을 사용하되, Eager 로딩 시 JOIN 쿼리 하나만 사용하지 않고, 다중 쿼리로 참조 객체를 로딩하여 N+1 문제를 방지.
5.Single Thread 기반:
•기본적으로 트랜잭션은 단일 스레드 환경에서 실행.
•Non-blocking Framework와 사용 시 I/O는 blocking될 수 있으나, Coroutine을 사용하여 비동기 작업 처리 가능.
6.Native Query 지원:
•필요시 네이티브 SQL 쿼리를 직접 작성 및 실행 가능.
7.Batch Update/Insert 지원:
•MySQL에서 JPA가 Identity Generator와 Context 문제로 지원하지 못하는 Batch 작업을 지원.
8.Spring @Transactional 지원:
•Spring 프레임워크의 @Transactional을 사용해 트랜잭션 관리 가능.
•트랜잭션 격리 수준(Isolation Level) 지정 가능.
•Propagation Level은 지원하지 않으나, NestedTransaction 플래그를 활성화해 부분적인 롤백 가능.
9.Multiple Datasource 지원:
•여러 데이터소스와 함께 사용할 수 있는 기능 지원.

장점

스프링 이외의 서버 프레임워크와 이용 가능 (ktor, http4k 등..)
코틀린으로 만들어져서 null 타입 호환이 잘 됨
batch insert 등을 편하게 쓸 수 있다.
jdbc template + jpa 느낌
설정이 간편하다.
coroutine transaction 을 지원함
팩토리 메소드,
정적, obj, 객체 반환,
빌더,
카자드 패턴, 서비스 분리할 타임 → 때 사용,
디자인 패턴사용, 그냥하다가 디자인 패턴을 사용할때 사용,