인프런 커뮤니티 질문&답변

플레어님의 프로필 이미지
플레어

작성한 질문수

스프링과 JPA 기반 웹 애플리케이션 개발

엔티티에 저장이 안되는 문제에 대한 문의

해결된 질문

작성

·

504

0

안녕하세요. 강의 잘 보았습니다. 강의 도움 받아서 테스트 진행해보고 있는데요. 저장이 안되는 부분에 대해 문의 드려봅니다.

Car, Camp 엔티티가 있고 Car 전체 데이터 읽어서 특정 필드의 값을  Camp 에서 찾아서 업데이트하는 로직입니다.

if (carRepository.count() > 0) {

carRepository.findAll().stream().forEach(s -> {
String campName = s.getCampEngName();
Optional<Car> car = carRepository.findById(s.getId());

Camp camp = campRepository.findByEngName(campName);
if (camp != null) {
car.ifPresent(m -> m.setNote(camp.getKorName()));
}
});
}

해당 부분 코드는 이렇게 했는데, 수행 후에 실제 Car 엔티티의 note 값이 변경이 안되어있습니다. 로그 찍어보면 campName 값은 일일이 잘 가져오고 있는데 setNote로 저장이 안됩니다.

트랜젝션 문제일까요? 강의를 제대로 소화를 못했는지 원인을 못찾겠네요. ㅠㅠ  도움 부탁드립니다.

아.. 저게 수행되는 곳이, 일반 컨트롤러 통해서 들어오는게 아니라 최초 실행시점입니다.(혹시 이게 문제일까요?)

@PostConstruct

public void initCarData() throws IOException {

...

if (carRepository.count() > 0) {

}

...

}

이 부분입니다.

답변 7

0

플레어님의 프로필 이미지
플레어
질문자

감사합니다.~

0

백기선님의 프로필 이미지
백기선
지식공유자

아 @PostConstruct를 쓴거였군요! 순서가 달라서 @Transactional이 적용이 안됩니다. 구체적으로는 @Transactional이 적용되려면 CarService의 프록시 객체가 만들어져야 가능한건데 그 작업은 @PostConstruct 실행하는 단계 이후에 벌어지는 일이라서 사실상 @Transactional없이 호출한거랑 같습니다. 다른 방법도 있긴하지만 이 경우에는 간단히 save()를 명시적으로 호출해주면 해결할 수 있긴합니다.

0

플레어님의 프로필 이미지
플레어
질문자

Optional<Car> car = carRepository.findById(s.getId());

아.. 저건 필요없는건데, 저거 없이 했을때 안돼서 이렇게 저렇게 시도해보는 중에 들어간 부분입니다.

원래소스는 아래와 같습니다. campName으로 조회한 Camp도 잘 가져옵니다.

@Service
@Transactional
@RequiredArgsConstructor
public class CarService {

private final CarRepository carRepository;
private final CampRepository campRepository;

@PostConstruct
public void initCarData() throws IOException {

if (carRepository.count() > 0) {
carRepository.findAll().stream().forEach(s -> {
String campName = s.getCampEngName();
Camp camp = campRepository.findByEngName(campName);
if (camp != null) {
addNote(s, camp);
}
});


}
}
public void addNote(Car car, Camp camp) {
System.out.println(">>>car = " +
"" + car.getCarNumber() + ", camp = " + camp + ", campId = " + camp.getId());
car.setNote(camp.getKorName());
}

}

-------------------------------
로그찍어보면 아래와같이 car 갯수만큼 잘 찍힙니다.

>>>car = 81조4766, camp = 광주2(GWJ2)/광주(Gwangju), campId = 45
>>>car = 83보8744, camp = 인천5(ICH5)/인천(Incheon), campId = 5


---------------------------------
근데, 컨트롤러에서 addNote 호출하면 정상적으로 저장이 됩니다.

0

백기선님의 프로필 이미지
백기선
지식공유자

그리고 campName은 잘 찍힌다고 하셨는데 혹시 그 campName으로 조회한 Camp도 잘 가져오는지 확인해 보셨나요?

0

백기선님의 프로필 이미지
백기선
지식공유자

해당 코드가 컨트롤러에 있다고 잘못 읽었네요. 죄송합니다.

우선 코드가 잘 이해가 안되는 부분이 있는데요. carRepository로 findAll을 했는데 하나씩 순회하면서 다시 id로 findById는 왜 하시는거죠? 

 Optional<Car> car = carRepository.findById(s.getId());

0

플레어님의 프로필 이미지
플레어
질문자

답변 감사합니다. 

해당 코드는 서비스 부분에 위치하고 있습니다. 서비스 전체코드는 아래와 같습니다.

클래스 상단에 @transaction 도 기재했고요. 이렇게 해도 안돼서 문의 드렸습니다. 

@Service
@Transactional
@RequiredArgsConstructor
public class CarService {

private final CarRepository carRepository;
private final CampRepository campRepository;

@PostConstruct
public void initCarData() {


if (carRepository.count() > 0) {

carRepository.findAll().stream().forEach(s -> {
String campName = s.getCampEngName();
Optional<Car> car = carRepository.findById(s.getId());

Camp camp = campRepository.findByEngName(campName);
if (camp != null) {
car.ifPresent(m -> addNote(m, camp));
}
});

}
}

}

0

백기선님의 프로필 이미지
백기선
지식공유자

트랜잭션이 있어야 퍼시스턴스 상태의 객체 변화를 감지(dirty checking)해서 트랜잭션 끝날 때 플러쉬 하면서 데이터 상태를 DB에 동기화 한다고 강좌에서 여러번 언급한거 같은데 아쉽네요. 해당 코드 블럭을 서비스로 옮기고 서비스 클래스나 해당 메서드 위에 @Transactional을 붙여보시기 바랍니다.

플레어님의 프로필 이미지
플레어

작성한 질문수

질문하기