Geneuin
Geneuin
2 min read

Categories

페이지 목차

  1. JPA 영속성에관하여 1
  2. JPA 영속성에관하여 2

JPA 영속성에관하여2


  • 안녕하세요. JPA를 활용하여 개발 중 일어난 문제점 중 영속성에 관하여 정리해보았습니다.

JPA를 활용하여 개발 중 업데이트 후 select 시 update 된 값이 반영되지 않는 문제가 발생하였습니다.

	@Transactional(propagation = Propagation.REQUIRED)
	public void updateTubeState(List<Tube> tubes) {
		for(Tube tube:tubes) {
			if(tube.getTubeState().getCodeId().equals("STATE-1")) {
				tubeService.updateTubeStateFail(tube);
			}else {
				tubeService.updateTubeState(tube);
			}
			Tube param = tubeService.findById(tube.getId());
			makeTubeLog(param);
		}
	}
  • 다음과 같은 이유가 뭘까를 찾기 위해 테스트코들을 작성하고 진행해보았습니다. 테스트를 위해 테스트 테이블 생성 후 다음과 같은 방법으로 진행해 보았습니다.
    @Table(name = "TEST")
    public class Test  {

        public Test(Long id) {
            this.id = id;
        }

        @Id
        @Column(name = "ID", nullable = false)
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;

        @Column(name = "TEST_TITLE", nullable = false, length = 200)
        private String testTitle;


    }
	@Transactional
	public void test(Test test) {
		testRepository.updateSubject(test,"change11");
		Optional<Test> result = testRepository.findById(test.getId());
		System.out.print(result.get().getTestTitle());
	}

  • 위와 같이 실험을 하니, 정상적으로 select 된 코드가 출력되었습니다. 문제가 무엇일까?? 그럼 기존 코드랑 테스트 코드랑 다른 점은 무엇일까?? 바로 영속성이었습니다. 테스트 코드는 영속성이 아닌 비영속상태의 객체를 생성하여 테스트하였기에 문제없이 진행되었습니다. 그럼 개발 중 오류 상태와 동일하게 만들기 위해 영속성을 만든 후 테스트해 보았습니다.
	@Transactional
	public void test(Test test) {
		test = testRepository.findById(test.getId()).get();
		testRepository.updateSubject(test,"change11");
		Optional<Test> result = testRepository.findById(test.getId());
		System.out.print(result.get().getTestTitle());
	}

  • 테스트 결과 업데이트한 subject가 findbyid를 통해 select시 출력되지 않았습니다. 로그 확인 결과 다음과 같은 결과가 나왔습니다.
    Hibernate: UPDATE TEST SET TEST_TITLE =? WHERE ID= ?
  • select 쿼리를 execute 하지 않았습니다. 아 그러면 select 문을 execute만 해주면 되겠구나. 생각하여 findbyid가 아닌 직접 nativequery select 코드를 만들어 select 해주었습니다.
	@Transactional
	public void test(Test test) {
		test = testRepository.findById(test.getId()).get();

		testRepository.updateSubject(test,"change11");
		Optional<Test> result = testRepository.select(test.getId());
		System.out.print(result.get().getTestTitle());
	}

    Hibernate: UPDATE TEST SET TEST_TITLE =? WHERE ID= ?
    Hibernate: SELECT * FROM TEST WHERE ID= ?
    before
  • log 결과 select를 해주었지만, return 된 값은 업데이트되지 않은 값이었습니다. 문제가 무엇일까 고민하고 search 결과 다음과 같은 결론에 도달하였습니다.

조회한 Entity에 이미 영속성이 존재한다면, query를 통해 조회한 결과를 버리고 영속성의 기존 결과를 반환한다. 1-1

  • 이러한 문제를 해결하기 위한 방법으로는 2가지 방법을 적용해보았습니다. 1)영속중인 객체에 직접 값을 업데이트 해주는 방법
	@Transactional
	public void test(Test test) {
		test = testRepository.findById(test.getId()).get();

		testRepository.updateSubject(test,"change11");
		test.setTestTitle("change11");
		//Optional<Test> result = testRepository.select(test.getId());
		System.out.print(result.get().getTestTitle());
	}

    Hibernate: UPDATE TEST SET TEST_TITLE =? WHERE ID= ?
    change11
    1. 영속성을 해제해 주는 방법 @Modifying(clearAutomatically = true) UPDATE 쿼리에 @Modifying의 clearAutomatically를 true해주면 영속성을 clear 해줍니다.
    @Transactional
	public void test(Test test) {
		test = testRepository.findById(test.getId()).get();

		testRepository.updateSubject(test,"change11");
		Optional<Test> result = testRepository.select(test.getId());
		System.out.print(result.get().getTestTitle());
	}

    @Modifying(clearAutomatically = true)
	@Query(value = "UPDATE TEST SET TEST_TITLE =:subject WHERE ID= :#{#test.id}", nativeQuery = true)
	void updateSubject(Test test, String subject);

    Hibernate: UPDATE TEST SET TEST_TITLE =? WHERE ID= ?
    Hibernate: SELECT * FROM TEST WHERE ID= ?
    change11