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 도 트랜잭션 환경이 유지되었다는 것이며, 이는 부모로부터 트랜잭션 환경을 물려 받아온 것으로 볼 수 있다.