spring: #띄어쓰기 없음
datasource: #띄어쓰기 2칸
url: jdbc:h2:tcp://localhost/~/jpashop #4칸
username: sa
password:
driver-class-name: org.h2.Driver
jpa: #띄어쓰기 2칸
hibernate: #띄어쓰기 4칸
ddl-auto: create #띄어쓰기 6칸
properties: #띄어쓰기 4칸
hibernate: #띄어쓰기 6칸
# show_sql: true #띄어쓰기 8칸
format_sql: true #띄어쓰기 8칸
logging.level: #띄어쓰기 없음
org.hibernate.SQL: debug #띄어쓰기 2칸
# org.hibernate.type: trace #띄어쓰기 2칸
application.yml은 위와 같다.
@Repository
public class MemberRepository {
@PersistenceContext
private EntityManager em;
public Long save(Member member){
em.persist(member);
return member.getId();
}
public Member find(Long id){
return em.find(Member.class ,id);
}
}
@PersistContext
애노테이션이 있으면 스프링부트가 EntityManager를 주입해준다.
em.persist(member)
의 반환값을 save
에서 반환하지 않는 이유는 side effect를 우려한 것이다.
@RunWith(SpringRunner.class)
@SpringBootTest
class MemberRepositoryTest {
@Autowired
MemberRepository memberRepository;
@Test
@Transactional
public void testMember() throws Exception{
// given
Member member = new Member();
member.setUsername("memberA");
System.out.println("member.getId() = " + member.getId()); // null
// when
Long savedId = memberRepository.save(member); // em.persist(member)
System.out.println("member.getId() = " + member.getId()); // 1 : 영속성 컨텍스트에서 값을 가져옴
Member findMember = memberRepository.find(savedId);
// then
Assertions.assertThat(findMember.getId()).isEqualTo(member.getId());
Assertions.assertThat(findMember.getUsername()).isEqualTo(member.getUsername());
Assertions.assertThat(findMember).isEqualTo(member); // 같은 트랜잭션 내에서 같은 id값인 엔티티는 ==비교가 true
}
}
@SpringBootTest
를 사용한다. @RunWith
로 스프링부트테스트로 돌린다는 것을 JUnit에게 알려준다.
@Transactional
은 EntityManager가 하는 모든 일은 트랜잭션 안에서 관리되어야 하기 때문에 필요하다. 리포지토리에 걸어줘도 되지만 일단은 테스트 메소드에 걸어준다.
테스트 케이스에 이 애노테이션이 있으면 테스트가 끝나고 바로 롤백을 해버리기 때문에 h2 db에 들어가서 확인해도 데이터가 없다.
테스트가 아닌 곳에 이 애노테이션이 있으면 롤백하지 않는다.
메소드 위에 @Rollback(false)
로 하고 돌리면 db에서 결과를 확인할 수 있다.
그리고 마지막 assertThat이 true가 나오는 이유는 한 트랜잭션 내에서 영속성 컨텍스트에서 같은 id 값을 갖는 엔티티는 ==
비교 했을때 true이기 때문이다.
영속성 컨텍스트에 있는 값을 가져왔기 때문