해결된 질문
작성
·
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
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을 붙여보시기 바랍니다.