문제 상황
회원가입 시 `user_tb`와 `user_account_tb` 두 테이블에 데이터를 저장해야 하는데, JPQL로는 한 번에 불가능
처음 작성한 코드
@Transactional
public void 회원가입(UserRequest.JoinDTO joinDTO) {
User user = joinDTO.toEntity(passwordEncoder);
userRepository.join(user);
UserAccount userAccount = joinDTO.toEntity(user);
userRepository.join2(userAccount);
}발생한 문제: user_account_tb의 user_id에 값이 채워지지 않음
원인 분석
- 트랜잭션 커밋 타이밍
- User 엔티티 저장 후 즉시 ID가 할당되지 않을 수 있음
- UserAccount 엔티티에서 User의 ID를 참조할 수 없는 상태
- 영속성 컨텍스트 플러시 미발생
- JPA는 트랜잭션 커밋 시점에 실제 INSERT 수행
- 중간에 ID가 필요한 경우 명시적 처리 필요

해결 방법
@Transactional로 두 Insert를 하나의 트랜잭션으로 묶기
@Service
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
@Transactional
public void 회원가입(UserRequest.JoinDTO joinDTO) {
// 1. User 엔티티 저장
User user = joinDTO.toEntity(passwordEncoder);
userRepository.join(user);
// 2. User 엔티티가 영속화되고 ID 생성됨// 3. 생성된 User를 참조하여 UserAccount 저장
UserAccount userAccount = joinDTO.toEntity(user);
userRepository.join2(userAccount);
}
}Repository 구현
@Repository
@RequiredArgsConstructor
public class UserRepository {
private final EntityManager em;
public void join(User user) {
em.persist(user);
// persist 후 User에 ID가 자동 할당됨
}
public void join2(UserAccount userAccount) {
em.persist(userAccount);
}
}작동 원리
1. @Transactional 시작
↓
2. User 엔티티 persist
→ JPA가 User에 ID 자동 할당 (영속성 컨텍스트)
↓
3. UserAccount 엔티티 생성 (User의 ID 참조 가능)
↓
4. UserAccount 엔티티 persist
↓
5. @Transactional 종료 → 실제 DB에 커밋
- `@Transactional`로 두 작업을 하나의 트랜잭션으로 묶음
- `em.persist()` 호출 시 ID가 영속성 컨텍스트에서 즉시 생성됨
- 순서가 중요: User 저장 → UserAccount 저장
Share article