Java : ORM, 영속성 컨텍스트

김선미·2022년 7월 20일
0

ORM

  • ORM (Object Relational Mapping)
    • object : 객체(java, python, javascript)
    • relational : DB (H2, MySQL)
    • Mapping : 객체와 DB를 연결하는 작업
  • JPA : java에서 사용하는 표준 ORM
  • 하이버네이트 : JPA를 구현한 프레임워크
  • Spring Data JPA : 스프링에서 Wrapping한 JPA

영속성 컨텍스트

  • JPA
    • Java 객체 - ORM - DB
    • Java 객체 - 영속성 컨텍스트 - DB

유저 생성

UserRepositoryTest

 @Order(1)
    @Test
    public void create() {
        // 회원 "user1" 객체 추가
        User user1 = new User();
        user1.setUsername("user1");
        user1.setPassword("password1");
        user1.setEmail("user1@sprata.com");
        user1.setRole(UserRole.USER);

        // 회원 "user1" 객체의 ID 값이 없다가..
        userRepository.save(user1);
        // DB 에 저장된 후, USER ID 값이 생김

        // 테스트 회원 데이터 삭제
        userRepository.delete(user1);
    }
  • 테이블 id 생성
    • userRepository.save(user1); 코드를 디버깅하면 save 이후 user1에 id가 생성된다. id는 테이블에서 유일무이한 값이어야 하고 DB에서 넘버링 등으로 유일무이한 값을 지정하도록 되어있다.

유저 조회, 삭제

UserController

 @GetMapping("/user/test/create")
    @ResponseBody
    public User test() {
        // 회원 "user1" 객체 추가
        User user1 = new User();
        user1.setUsername("user1");
        user1.setPassword("password1");
        user1.setEmail("user1@sprata.com");
        user1.setRole(UserRole.USER);
        // 회원 "user1" 객체를 영속화
        userRepository.save(user1);

        // 회원 "user1" 을 조회
        User foundUser1 = userRepository.findByUsername("user1").orElse(null);
        // 회원 "user1" 을 또 조회
        User foundUser2 = userRepository.findByUsername("user1").orElse(null);
        // 회원 "user1" 을 또또 조회
        User foundUser3 = userRepository.findByUsername("user1").orElse(null);
  • UserRepositoryTest 에서 객체를 조회할때 foundUser1,2,3 객체에 서로 다른 아이디가 부여되었지만 컨트롤러 환경에는 영속성 컨텍스트가 존재하여 foundUser1,2,3 을 조회해도 1차 캐시에 저장한 같은 아이디만이 부여된다. 즉 findByUsername 메소드를 실행하면 DB에 직접 조회하지 않고 영속성 컨텍스트에 저장된 캐시를 조회한다.
  • 영속성 컨텍스트는 DB에 저장한 값을 id로 기억한다.
  • 영속성 컨텍스트는 1차 캐시를 사용하여 객체가 1개로 사용되는 동일성을 보장한다.
    userRepository.delete(user1);
  • DB에서 데이터를 삭제하면 영속성 컨텍스트에서도 사라진다.

유저 수정

  • 객체를 변경해도 변경사항은 DB에 반영되지 않으므로 객체를 DB에 저장하는 함수를 실행 해주어야한다.
@GetMapping("/user/test/update/2")
@ResponseBody
public User updateUser2() {
    // 테스트 회원 "user1" 생성
    createTestUser1();

    // 회원 "user1" 객체 추가
    // 회원 "user1" 을 조회
    User user1 = userRepository.findByUsername("user1").orElse(null);
    // 회원 "user1" 이 존재하면,
    if (user1 != null) {
        // 회원의 email 변경
        user1.setEmail("updateUser1@sparta.com");
        // 회원의 role 변경 (USER -> ADMIN)
        user1.setRole(UserRole.ADMIN);
    }

    // user1 을 저장
    userRepository.save(user1);
}
  • @Transactional 어노테이션을 사용하면 DB에 직접 저장하는 코드를 구현하지 않아도 객체 변경사항을 DB에 반영해준다.
  • 아래 메소드를 실행하면 DB에서 조회한 user1을 저장하고 있다가 변경사항과 비교를 하고 변경된 사항이 있다면 메소드가 끝날 때 DB에 저장해준다.
@GetMapping("/user/test/update/3")
@ResponseBody
@Transactional
public void updateUse3() {
    // 테스트 회원 "user1" 생성
    createTestUser1();

    // 회원 "user1" 객체 추가
    // 회원 "user1" 을 조회
    User user1 = userRepository.findByUsername("user1").orElse(null);
    // 회원 "user1" 이 존재하면,
    if (user1 != null) {
        // 회원의 email 변경
        user1.setEmail("updateUser1@sparta.com");
        // 회원의 role 변경 (USER -> ADMIN)
        user1.setRole(UserRole.ADMIN);
    }
}
profile
백엔드 개발 공부

0개의 댓글