spring.jpa.open-in-view
true 가 기본값
true 일때는, transaction 이 끝나더라도 영속성 컨텍스트를 유지하고 있음. (데이터 베이스 커넥션을 유지)
화면이 렌더링 될때까지 혹은, Api 값이 반환 될때까지!
그래야, transaction 사용하는 서비스 계층 외부에서 사용되는 것들에서 활용이 가능하기 때문에!!
Lazy 로딩 을 할 수 있는 등, 데이터베이스 커넥션을 유지해준다!!
그런데 이 전략은... 오랜시간동안 데이터베이스 커넥션 리소스를 사용하기 때문에, 실시간 트래픽이 중요한 애플리케이션에서는 커넥션이 모자랄 수 있음!! -> 이는 장애로 이어질 수 있다.
만약 api Controller 에서 외부 API 를 반환하게 되면, 그 시간 만큼 커넥션 리소스를 붙잡고 있게 되고, 이는 리소스의 부족을 야기!!
데이터 베이스 커넥션 리소스를 낭비하지 않음!
하지만 lazy 로딩 같은 기능들은 트랜잭션 내 에서 해결이 되어야함!
트랜잭션 외부에서 쉽게 사용하던 것들을 트랜잭션 내부로 옮겨야함
기존에 lazy 로딩으로 잘 되던것들이, proxy 객체로 넘어오게 됨! (에러)
이 서비스 계층에서 모든 걸 처리한 뒤에,
Controller 로 내보내기!!
이런식으로 따로 만들어서, 최종적으로 데이터가 다 담겨 있는 데이터를 넘겨주기!!
커맨드와 쿼리를 구분하는 것이 좋다
- 커맨드 : C, U, D
- 쿼리 : Read (조회)
보통의 성능 문제는 쿼리에서 일어남!!
이 둘을 분리하는 것은 유지보수 관점에서 충분히 의미 있음.
고객 서비스의 실시간 API 는 OSIV 를 끄고
ADMIN 사이트 처럼 커넥션을 많이 사용하지 않는 곳에서는 OSIV 를 켠다.
기본적으로 중복되는 메소드들을 줄이기 위해, 시작한 프로젝트!!
기존 <MemberRepository.java>
@Repository
@RequiredArgsConstructor
public class MemberRepository {
private final EntityManager em;
public void save(Member member){
em.persist(member);
}
public Member findOne(Long id){
return em.find(Member.class, id);
}
public List<Member> findAll(){
return em.createQuery("select m from Member m", Member.class).getResultList();
}
public List<Member> findByName(String name){
return em.createQuery("select m from Member m where m.name= :name", Member.class)
.setParameter("name", name)
.getResultList();
}
}
이후 <MemberRepository.java>
public interface MemberRepository extends JpaRepository<Member, Long> {
List<Member> findByName(String name);
}
Repository 들이 기본적으로 제공할 것 같은 것들 메소드로 싹 저장 되어 있음!!
심지어 findByName
도 메소드 이름을 보고, 알아서 완성된다!
=> select m from Member m where m.name = :name
으로 jpql 쿼리
다른 계층에서 사용하는 findOne()
은 findById()
로 바꾸어 주면 됨!
// 이전
return memberRepository.findOne(memberId);
// 이후
return memberRepository.findById(memberId).get();
interface 로 해놔도, spring에서 알아서 주입을 해줌!!
jpql 쿼리를 java 문법으로 바꿈!
QueryDSL 을 사용하려면 build.gradle 에 dependencies 추가해줘야함
//querydsl 추가
buildscript {
ext {
queryDslVersion = "5.0.0"
}
}
plugins {
id 'java'
id 'org.springframework.boot' version '2.7.10'
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
//querydsl 추가
id 'com.ewerk.gradle.plugins.querydsl' version '1.0.10'
}
group = 'jpabook'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-devtools'
implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.6'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-hibernate5'
testImplementation 'junit:junit:4.13.1'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
//querydsl 추가
implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"
implementation "com.querydsl:querydsl-apt:${queryDslVersion}"
}
tasks.named('test') {
useJUnitPlatform()
}
//querydsl 추가
def querydslDir = 'src/main/generated'
//def querydslDir = "$buildDir/generated/querydsl"
querydsl {
library = "com.querydsl:querydsl-apt"
jpa = true
querydslSourcesDir = querydslDir
}
sourceSets {
main {
java {
srcDirs = ['src/main/java', querydslDir]
}
}
}
compileQuerydsl {
options.annotationProcessorPath = configurations.querydsl
}
configurations {
querydsl.extendsFrom compileClasspath
}
public List<Order> findAllByQueryDSL(OrderSearch orderSearch){
QOrder order = QOrder.order;
QMember member = QMember.member;
JPAQueryFactory query = new JPAQueryFactory(em);
return query.select(order)
.from(order)
.join(order.member, member)
.limit(1000)
.fetch();
}
메소드 체인으로 쉽게 구현 가능!
문자열 에러 걱정할 필요도 없음!!
이런 식들로 메소드 안에서 편하게 condition 적용 가능!
(이런건 재사용도 됨)
QueryDSL generate 된 파일들은 .gitignore 에 포함시키기!!