Blog

[Spring]25 SpringBoot 환경에서의 JPA 사용을 위한 환경 설정과 영속성(Managed) 상태 등 CRUD가 가능한 Transaction 환경 개념의 사용법과 작동 테스트

Author
Summary
Spring Boot의 JPA 사용 테스트
Category
Study
Tags
Spring
Favorite
Memory Date
2023/09/02
Cross Reference Study
Related Media
Related Thought
Related Lessons
tag
날짜
작성자
진행상황
진행 전
태그구분
6 more properties
Dependencies에 Spring JPA 라이브러리 추가
build.gradle
dependencies { // MySQL implementation 'mysql:mysql-connector-java:8.0.28' // JPA 구현체인 hibernate implementation 'org.hibernate:hibernate-core:6.1.7.Final' // JDBC // implementation 'org.springframework.boot:spring-boot-starter-data-jdbc' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' }
Java
복사
이후 JDBC 라이브러리는 필요없어진다. 해당 라이브러리에 이미 JDBC가 존재하기 때문
SpringBoot 환경에서는 EntityManagerFactory와 EntityManager를 자동으로 생성해준다
Java환경에서 EMF를 통해 EM이 생성되고 EM이 Action Queue, persistenceContext 등을 관리하게 되는데, Spring에서는 그 EM생성까지도 자동으로 생성해준다(어노테이션으로 주입된 클래스에 구현되어있다는 소리)
application.properties에 DB 정보를 전달해 주면 이를 토대로 EntityManagerFactory가 생성된다.
@PersistenceConext 애너테이션을 사용하면 자동으로 생성된 EntityManager를 주입받아 사용할 수 있습니다.
Java에서 테스트해봤던 Transaction 개념은 Spring에서 사용하는가?
Java환경에서 DB의 트랜잭션을 통해서 마치 임시저장소에 영속성(MANAGED) 처럼 저장하고, DB로부터 불러오고, 또 영속성으로 만들었다가 준영속성으로 풀어주기도 하고, 닫기도 하고 업데이트 할 때 필수적으로 사용되었던 Transaction 개념은 객체의 무결성을 보장하기 좋은 개념으로 이해했다. Spring의 JPA도 그 개념을 어떻게 사용하는지 궁금하다.
Spring 프레임워크에서는 DB의 트랜잭션 개념을 애플리케이션에 적용할 수 있도록 트랜잭션 관리자를 제공하고 있다.
@Transactional 애너테이션을 클래스나 메서드에 추가하면 쉽게 트랜잭션 개념을 적용
Spring에서는 Service-Repository 2개 구간에서 트랜잭션이 필요하다. Spring은 2개 구간을 어떻게 유지 할 수 있도록 구현하는가?
테스트 코드를 통해서 트랜잭션 환경이 아닌 상태에선 em의 persist(object)로 객체를 영속성(MANAGED) 하려하면 오류가 곧바로 발생하는 것을 볼 수 있다.
@Test @Disabled // 이건 실패라 오류가 계속되니 메소드 사용하지 않도록 설정, 다시 테스트할땐 지우기 @DisplayName("메모 생성 실패") //cannot reliably process 'persist' call 트랜잭션이 없어서 ! 오류발생 void test2() { Memo memo = new Memo(); memo.setUsername("Robbie"); memo.setContents("@Transactional 테스트 중!"); em.persist(memo); // 영속성 컨텍스트에 메모 Entity 객체를 저장합니다. }
Java
복사
위 그림처럼 DB직접 연관있는 Repository와 Service는 계속해서 Persistence Context에서 객체가 임시 저장소에 관리받고있는 영속성(MANAGED)을 유지 할 수 있어야 한다. 그럼 그것은 Transaction 환경이 두 레이어 모두 유지가 되고 있어야 한다는 말과 같다.
Transaction의 실행 및 전파
@Transactional 어노테이션으로 해당 클래스의 Transaction 환경을 시작 할 수 있다. (== 해당 메소드가 종료되면 Commit 된다는 소리와 같음)
부모메서드에 @Transactional 어노테이션으로 트랜잭션이 활성화 되있으면, 자손메소드도 트랜잭션도 이어진다(전파된다)
부모 메소드 Test 코드 TransactionTest.java
@Test @Transactional //만약에 부모가 없는 경우에 테스트해보면, create(3)으로 전파안됨 /기본 Required 옵션, 부모메서드에 트랜잭션이 되있으면, 자손메소드도 트랜잭션도 이어진다(전파된다) @Rollback(value = false) @DisplayName("트랜잭션 전파 테스트") void test3() { memoRepository.createMemo(em); //더이상 테스트안하니까 이것 미사용 System.out.println("테스트 test3 메서드 종료"); }
Java
복사
비활성화 시켜둔 자손 메소드 MemoRepository.java
//트랜잭션 전파 예시 //@Transactional //기본 Required 옵션, 부모메서드에 트랜잭션이 되있으면, 자손메소드도 트랜잭션도 이어진다(전파된다) public Memo createMemo(EntityManager em) { Memo memo = em.find(Memo.class, 1); memo.setUsername("Robbie"); memo.setContents("@Transactional 전파 테스트 중!"); System.out.println("createMemo 메서드 종료"); return memo; }
Java
복사
전파 되었는지 증거는 이름과 내용이 “Robbie”,”@Transactional 전파 테스트 중!”이라는 것이 DB에 적용 되었는지가 확인되면 되고 “createMemo메서드 종료”라는 메시지가 나타나면 해당 자손 메소드를 들어갔다 나온 것인데 테스트 결과는 다음처럼
Hibernate: select m1_0.id, m1_0.contents, m1_0.username from memo m1_0 where m1_0.id=? createMemo 메서드 종료 테스트 test3 메서드 종료 Hibernate: /* update for com.sparta.memo.entity.Memo */update memo set contents=?, username=? where id=?
Java
복사
“createMemo메서드 종료”라는 메시지와 실제 DB에서도 set내용이 업데이트 된 것을 확인 할 수 있었다. 따라서 주석처리한 MemoRepository.java 도 트랜잭션 환경이 유지되었다는 것이며, 이는 부모로부터 트랜잭션 환경을 물려 받아온 것으로 볼 수 있다.