본문 바로가기
Spring/02. Repository

객체의 특정 필드에 값이 없는 상태로 db에 저장하고나서 값이 생긴 경우

by 989898 2025. 2. 13.
    private Member(Long mbNo, String mbEmail, String mbName, String mbPassword, String mbMobile, LocalDateTime createdAt, LocalDateTime updatedAt, LocalDateTime withdrawalAt) {
        this.mbNo = mbNo;
        this.mbEmail = mbEmail;
        this.mbName = mbName;
        this.mbPassword = mbPassword;
        this.mbMobile = mbMobile;
        this.createdAt = createdAt;
        this.updatedAt = updatedAt;
        this.withdrawalAt = withdrawalAt;
    }   

	public static Member ofNewMember(String mbEmail, String mbName, String mbPassword, String mbMobile) {
        return new Member(null, mbEmail, mbName, mbPassword, mbMobile, null, null, null);
    }

 

@Test
    @DisplayName("회원등록")
    void save() {

        // 새 회원 저장 시 데이터베이스에 회원 정보가 정상적으로 저장되는지 검증
        // 저장 후, 데이터베이스에서 회원 정보를 조회하여 저장된 데이터와 일치하는지 확인
		
        // 각 객체에 mbNo 없는 상태로 저장
        Member member1 = Member.ofNewMember("marco@nhnacademy.com","마르코","12345","01012345678");
        Member member2 = Member.ofNewMember("test@nhnacademy.com","테스트","12345","01011112222");

        memberRepository.save(member1);
        memberRepository.save(member2);
		
        // mbNo 없는 상태로 저장했는데 저장 후 객체에 mbNo가 존재함.
        System.out.println(member1.getMbNo() + "멤버 넘버!!!!!!!!!!!!!!!!!!!!!!");
        System.out.println(member2.getMbNo() + "멤버 넘버!!!!!!!!!!!!!!!!!!!!!!");

        Optional<Member> actualOptionalMember1 = memberRepository.findByMbNo(member1.getMbNo());
        Optional<Member> actualOptionalMember2 = memberRepository.findByMbNo(member2.getMbNo());

        Assertions.assertTrue(actualOptionalMember1.isPresent());
        Assertions.assertTrue(actualOptionalMember2.isPresent());

        log.debug("member1: {}", actualOptionalMember1.get());
        log.debug("member2: {}", actualOptionalMember2.get());

        Assertions.assertAll(
                ()->Assertions.assertNotNull(actualOptionalMember1.get()),
                ()->Assertions.assertEquals(member1.getMbEmail(), actualOptionalMember1.get().getMbEmail()),
                ()->Assertions.assertEquals(member1.getMbName(), actualOptionalMember1.get().getMbName()),
                ()->Assertions.assertEquals(member1.getMbPassword(), actualOptionalMember1.get().getMbPassword()),
                ()->Assertions.assertEquals(member1.getMbMobile(), actualOptionalMember1.get().getMbMobile()),
                ()->Assertions.assertNotNull(actualOptionalMember1.get().getCreatedAt()),

                ()->Assertions.assertNotNull(actualOptionalMember2.get()),
                ()->Assertions.assertEquals(member2.getMbEmail(), actualOptionalMember2.get().getMbEmail()),
                ()->Assertions.assertEquals(member2.getMbName(), actualOptionalMember2.get().getMbName()),
                ()->Assertions.assertEquals(member2.getMbPassword(), actualOptionalMember2.get().getMbPassword()),
                ()->Assertions.assertEquals(member2.getMbMobile(), actualOptionalMember2.get().getMbMobile()),
                ()->Assertions.assertNotNull(actualOptionalMember2.get().getCreatedAt())
        );
    }

 

출력 결과

870멤버 넘버!!!!!!!!!!!!!!!!!!!!!!
871멤버 넘버!!!!!!!!!!!!!!!!!!!!!!

 

테스트 코드에서 member1 member2 객체를 생성할 때 mbNo(회원 번호)는 null로 설정됩니다. 하지만 memberRepository.save() 메서드를 호출한 이후에 mbNo에 값이 저장되는 이유는 레포지토리의 save() 메서드가 데이터베이스와 상호작용하면서 객체의 상태를 업데이트하기 때문입니다.

 mbNo가 저장되는가?

1. 데이터베이스에서 자동으로 생성된 ID

  • 일반적으로 데이터베이스 테이블에서 기본 키(Primary Key)는 자동 증가(AUTO_INCREMENT) 속성을 가지며, 새로운 레코드가 삽입될 때 데이터베이스가 고유한 ID 값을 생성합니다.
  • 예를 들어, MySQL에서 다음과 같은 테이블 정의가 있을 수 있습니다:
  • save() 메서드가 호출되면, 데이터베이스에 새로운 레코드가 삽입되고, 이 과정에서 데이터베이스가 자동으로 ID 값을 생성하여 반환합니다.

2. 레포지토리의 save() 메서드 동작

  • save() 메서드는 보통 다음과 같은 작업을 수행합니다:
    1. 객체를 데이터베이스에 저장:
      • SQL INSERT 문을 실행하여 데이터를 삽입합니다.

예 :

 
INSERT INTO member (mb_email, mb_name, mb_password, mb_mobile)
VALUES ('marco@nhnacademy.com', '마르코', '12345', '01012345678');

 

    1. 생성된 ID를 객체에 설정:
      • 데이터베이스는 새로 생성된 ID 값을 반환합니다(예: MySQL의 LAST_INSERT_ID()).
      • 이 ID 값은 member1 객체의 mbNo 필드에 설정됩니다.

예 : 

member1.setMbNo(generatedId);
 

3. JPA 또는 ORM 프레임워크의 동작

  • 만약 프로젝트에서 JPA나 Hibernate 같은 ORM(Object-Relational Mapping) 프레임워크를 사용하고 있다면, 다음과 같은 방식으로 작동합니다:
    • 엔티티 객체(Member)를 영속성 컨텍스트에 저장할 때, JPA는 데이터베이스에 INSERT 쿼리를 실행하고 자동 생성된 ID 값을 엔티티 객체의 필드(mbNo)에 매핑합니다.
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long mbNo;
 

테스트 코드에서의 흐름

  1. ofNewMember() 호출:
    • member1 member2 객체를 생성하며, 이때 mbNo null로 초기화됩니다.
  2. memberRepository.save() 호출:
    • 새 회원 정보를 데이터베이스에 저장합니다.
    • 데이터베이스는 각 회원에 대해 고유한 ID 값을 생성하고 반환합니다.
    • 반환된 ID 값은 member1 member2 객체의 mbNo 필드에 설정됩니다.
  3. 출력 결과:
    • System.out.println(member1.getMbNo() + "멤버 넘버!!!!!!!!!!!!!!!!!!!!!!");
    • 이 시점에서 mbNo는 더 이상 null이 아니며, 데이터베이스에서 생성된 고유한 값(예: 870, 871)이 출력됩니다.

왜 이런 설계가 필요한가?

  1. 데이터 무결성 보장:
    • 회원 번호(mbNo)는 고유해야 하며, 이를 보장하기 위해 데이터베이스에서 자동으로 관리하는 것이 일반적입니다.
  2. 객체와 데이터베이스 동기화:
    • 레포지토리의 save() 메서드는 데이터베이스와 애플리케이션 객체 간의 상태를 동기화하여, 애플리케이션이 항상 최신 상태의 데이터를 사용할 수 있도록 합니다.
  3. 편리한 테스트 및 개발:
    • 테스트 코드에서는 ID 값을 직접 설정하지 않아도 되므로 간결한 코드를 작성할 수 있습니다.
    • 동시에, 저장 후에는 자동으로 ID 값이 설정되므로 이후 로직에서 이를 활용할 수 있습니다.

결론

테스트 코드에서 member1.getMbNo()와 같이 출력했을 때 값이 존재하는 이유는:

  • 데이터베이스가 새로운 회원 번호(mbNo)를 자동으로 생성했기 때문입니다.
  • 레포지토리의 save() 메서드가 이 값을 반환받아 객체(member1, member2)의 필드에 설정했기 때문입니다.

이 설계는 데이터 무결성과 편리한 개발을 위해 일반적으로 사용되는 패턴입니다.


 

 

 

 

 

'Spring > 02. Repository' 카테고리의 다른 글

02. Repository Test  (0) 2025.02.11
01. Repository 개발  (1) 2025.02.11