6 분 소요



2023.04.17 수정됨.


어노테이션 정리

  • @GeneratedValue 어노테이션? :

@GeneratedValue 어노테이션은 JPA에서 Entity 클래스의 기본 키를 자동으로 생성하기 위해 사용됩니다. 이 어노테이션은 @Id 어노테이션과 함께 사용되며, strategy 속성을 통해 어떤 방식으로 기본 키를 생성할지 설정할 수 있습니다.

그러면 strategy 속성에는 어떤 값이 있을까? ↓ 대표적인 값 3가지

  1. GenerationType.IDENTITY: 데이터베이스에서 기본 키 생성을 처리합니다. 예를 들어 MySQL에서는 AUTO_INCREMENT를 사용하여 기본 키를 생성합니다.
  2. GenerationType.SEQUENCE: 데이터베이스 시퀀스를 사용하여 기본 키를 생성합니다. 이 방식은 Oracle과 같은 몇몇 데이터베이스에서 사용할 수 있습니다.
  3. GenerationType.TABLE: 데이터베이스의 특별한 테이블에서 기본 키 값을 가져옵니다. 이 방식은 모든 데이터베이스에서 사용할 수 있습니다.


나는 MySQL을 사용할것이기에 IDENTITY 속성을 사용할 것이다.

GenerationType.IDENTITY는 매우 일반적인 전략으로, 대부분의 데이터베이스에서 지원됩니다. 다른 전략은 데이터베이스의 종류나 설정에 따라 지원되지 않을 수도 있습니다. 기본 키를 생성하는 방식은 JPA 구현체에서 지원하는 방식과 데이터베이스 종류 및 설정에 따라 달라질 수 있습니다.


예를 들어, 다음과 같이 Entity 클래스를 작성하면 GenerationType.IDENTITY를 사용하여 MySQL에서 자동으로 기본 키를 생성할 수 있습니다.

public class User {
 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
}



  • 🔑 @ElementCollection 이란?

    JPA에서는 엔티티 클래스와 관련된 테이블을 자동으로 생성해주는데, 이때 필드와 컬럼을 매핑해주는 어노테이션을 사용합니다.

    @ElementCollection 어노테이션은 엔티티에서 컬렉션을 매핑하는 데 사용됩니다. 예를 들어, 아래와 같이 User 엔티티 클래스에 List<String> 타입의 roles 필드가 있다고 가정해보겠습니다.

    @Entity
    public class User {
        @Id
        private Long id;
        private String name;
          
        @ElementCollection
        private List<String> roles;
        // ...
    }
      
    

    이 경우 roles 필드는 @ElementCollection 어노테이션을 사용하여 엔티티에서 컬렉션으로 매핑됩니다.

    JPA는 User 테이블 외에도 User_roles와 같은 이름의 테이블을 자동으로 생성하여 User 엔티티와 roles 컬렉션을 매핑해줍니다. 이때 User_roles 테이블은 idvalue 두 개의 컬럼을 가지며, id 컬럼은 User 엔티티의 기본 키인 id와 매핑되고, value 컬럼은 roles 컬렉션의 각 원소와 매핑됩니다.

    따라서, @ElementCollection 어노테이션은 엔티티에서 컬렉션을 매핑하여, 엔티티 클래스와 컬렉션을 매핑하는 중간 테이블을 자동으로 생성해줍니다. 이를 통해 객체지향 프로그래밍에서 사용하는 컬렉션을 데이터베이스에 저장할 수 있습니다.


    결과적으로는 @ElementCollection 어노테이션을 사용하여 컬렉션을 매핑할 때, 해당 컬렉션의 원소들은 별도의 테이블에 저장됩니다. 이때 @ElementCollection 어노테이션을 사용한 필드가 속한 엔티티 클래스의 @Id 어노테이션이 적용된 필드와 같은 기본 키를 공유합니다. 따라서, 컬렉션의 원소들이 저장될 때 엔티티 클래스와 컬렉션의 원소들이 매핑되는 테이블에 @Id 어노테이션으로 지정한 필드값과 함께 저장되어, 엔티티 객체와 컬렉션 객체를 서로 연결할 수 있게 됩니다.


    직관적인 예시 위 같은 코드가 있다면,

    +-------------+
    |  user_roles |
    +-------------+
    | user_id (PK) |
    | value       |
    +-------------+
      
    

    User 엔티티와 roles 컬렉션을 매핑하는 중간 테이블인 user_roles 테이블은 다음과 같이 생성됩니다.

    여기서 user_id 컬럼은 User 엔티티의 기본 키인 id와 매핑되며, value 컬럼은 roles 컬렉션의 각 원소와 매핑됩니다. 따라서, User 엔티티 객체의 id 필드와 roles 컬렉션 객체의 각 원소가 매핑되는 user_roles 테이블에는 다음과 같은 데이터가 저장됩니다.


    +---------+-------+
    | user_id | value |
    +---------+-------+
    |       1 | USER  |
    |       1 | ADMIN |
    +---------+-------+
      
    

    위의 예시에서 User 엔티티의 id 필드값이 1이라고 가정합니다. 이때 roles 컬렉션에는 “USER”와 “ADMIN”이라는 두 개의 원소가 포함되어 있습니다. @ElementCollection 어노테이션을 사용하여 roles 필드를 매핑하면, 이 컬렉션의 각 원소는 user_roles 테이블에 저장됩니다. 저장될 때 User 엔티티의 id 필드값과 함께 저장되어, User 엔티티 객체와 roles 컬렉션 객체를 서로 연결할 수 있게 됩니다.



    그러면 여기에서 fetch는 뭘까?

     @ElementCollection(fetch = FetchType.EAGER)
    

    fetch 속성은 @ElementCollection 어노테이션과 함께 사용하여 컬렉션을 로드할 때 어떻게 로드할지를 설정합니다. fetch 속성은 다음과 같은 옵션을 가질 수 있습니다.

    • FetchType.EAGER: 즉시 로드합니다. User 엔티티를 조회할 때 roles 컬렉션을 함께 조회합니다.
    • FetchType.LAZY: 지연 로드합니다. User 엔티티를 조회할 때 roles 컬렉션은 로드하지 않고, 실제로 사용될 때 로드됩니다.

    따라서 @ElementCollection(fetch = FetchType.EAGER)User 엔티티를 조회할 때 roles 컬렉션도 함께 조회하도록 설정하는 것입니다. 이렇게 함으로써, User 엔티티 객체와 함께 roles 컬렉션 객체도 로드되므로, roles 컬렉션에 접근할 때 지연 로딩으로 인한 성능 문제를 피할 수 있습니다.

    반면에 @ElementCollection(fetch = FetchType.LAZY)를 사용하면, User 엔티티를 조회할 때 roles 컬렉션은 로드되지 않습니다. 대신, roles 컬렉션에 실제로 접근할 때 로드됩니다. 이 방법은 roles 컬렉션이 큰 경우 성능을 향상시킬 수 있습니다.

  • @Data 어노테이션

    @Data는 Lombok에서 제공하는 애노테이션 중 하나로, 클래스 내의 필드들에 대해 Getter, Setter, ToString, EqualsAndHashCode, RequiredArgsConstructor 등의 메서드를 자동으로 생성해주는 기능을 제공합니다.

    보통 DTO, VO 등의 객체를 정의할 때, 클래스 내에 필드를 선언하고 각각의 Getter, Setter 메서드를 만들어주어야 하는데, 이를 @Data 애노테이션을 사용하면 자동으로 생성해줍니다. 따라서 개발자는 필드의 정의만 해주면 됩니다.

    @Data 애노테이션은 다른 Lombok 애노테이션과 함께 사용하면 더욱 편리합니다. 예를 들어, @NoArgsConstructor와 함께 사용하면 기본 생성자를 자동으로 생성해주고, @AllArgsConstructor와 함께 사용하면 모든 필드를 인자로 받는 생성자를 자동으로 생성해줍니다. 또한, @ToString 애노테이션과 함께 사용하면 toString() 메서드를 자동으로 생성해주고, @EqualsAndHashCode 애노테이션과 함께 사용하면 equals()와 hashCode() 메서드를 자동으로 생성해줍니다.

    @Data 애노테이션을 사용하면 개발자가 직접 Getter, Setter, toString(), equals(), hashCode() 등을 작성하지 않아도 되므로, 코드의 간결성과 가독성을 높일 수 있습니다.




메서드 정리

  • .and() : .and() 메서드는 HttpSecurity 빌더의 체인 빌딩을 가능하게 합니다. HttpSecurity 객체는 Spring Security 구성을 구현하는 데 사용되며, 구성은 체인 빌더 패턴을 사용하여 이루어집니다. 이 때, and() 메서드는 이전 메서드가 구성한 보안 구성의 일부분을 구성하는 데 사용됩니다. 즉, and() 메서드는 이전 보안 구성에 대한 계속적인 설정이 가능하도록 하기 위해 사용됩니다.




단어정리

  • 파싱 : 파싱(Parsing)은 어떤 데이터나 텍스트에서 특정한 패턴을 찾아내어 그것을 해석하거나 분석하는 것을 말합니다. 예를 들어, 웹 서버가 클라이언트로부터 받은 HTTP 요청 메시지를 해석해서 요청한 페이지의 정보를 파악하거나, 프로그래밍에서 문자열에서 원하는 정보를 추출하기 위해 문자열 파싱을 수행하는 등의 작업에서 사용됩니다. 파싱은 데이터를 처리하거나 분석하는데 중요한 기술 중 하나입니다.
  • JwtTokenizer: JWT(Json Web Token)를 생성하고 파싱하는 역할을 합니다.
  • CustomUserDetailsService: Spring Security의 UserDetailsService를 구현한 커스텀 서비스로, 사용자 정보를 데이터베이스에서 조회하고 인증에 필요한 정보를 제공합니다.
  • OAuth2UserDetailsService: OAuth2 로그인 시 사용자 정보를 가져오기 위한 서비스로, OAuth2 프로바이더의 API를 호출하여 사용자 정보를 가져옵니다.
  • OAuth2UserSuccessHandler: OAuth2 로그인 성공 후에 실행되는 핸들러로, 사용자 정보를 인증서버에 저장하거나 필요한 처리를 수행합니다.
  • 파라미터 : 파라미터(parameter)는 함수나 메서드 등에서 입력값을 전달받는 변수를 말합니다. 함수나 메서드를 호출할 때, 인자(argument)라고도 불리우는 값을 전달하면 이 값이 함수나 메서드 내부의 파라미터로 전달되어 처리됩니다. 파라미터를 이용하면 함수나 메서드가 실행될 때 동적으로 데이터를 전달할 수 있습니다.
  • Cascade?

    JPA에서 엔티티 객체의 상태를 변경할 때, 해당 객체와 연관된 다른 객체들의 상태도 함께 변경해야 하는 경우가 있습니다. 이런 경우에 CascadeType 속성을 사용하여 연관된 객체들의 상태도 함께 변경할 수 있습니다.

    CascadeType은 다음과 같은 값들을 가질 수 있습니다.

    • CascadeType.PERSIST : 새로운 객체를 저장할 때 연관된 객체도 함께 저장합니다.
    • CascadeType.MERGE : 객체를 수정할 때 연관된 객체도 함께 수정합니다.
    • CascadeType.REMOVE : 객체를 삭제할 때 연관된 객체도 함께 삭제합니다.
    • CascadeType.REFRESH : 객체를 새로고침할 때 연관된 객체도 함께 새로고침합니다.
    • CascadeType.ALL : 위 모든 동작을 수행합니다.

    CascadeType@OneToOne, @OneToMany, @ManyToOne, @ManyToMany 어노테이션과 함께 사용할 수 있으며, 필요에 따라 해당하는 옵션을 선택하여 사용할 수 있습니다.

    예를 들어 User 엔티티 클래스에서 CascadeType.ALL을 설정한 경우, User 객체의 상태가 변경될 때 연관된 Reputation 객체의 상태도 함께 변경되며, User 객체가 삭제될 때 연관된 Reputation 객체도 함께 삭제됩니다.


    예를들어

    @OneToManyCascadeType.ALL을 사용해보면,

    @Entity
    public class User {
        // ...
      
        @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
        private List<Post> posts = new ArrayList<>();
          
        // ...
    }
      
    @Entity
    public class Post {
        // ...
      
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "user_id")
        private User user;
      
        // ...
    }
      
    

    위 예시에서 User 엔티티는 여러 개의 Post 엔티티를 가지며, Post 엔티티는 하나의 User 엔티티에 속합니다. User 엔티티에서 posts 필드는 Post 엔티티와 일대다 관계를 가지며, mappedBy 속성으로 Post 엔티티의 user 필드와 매핑됩니다. cascade 속성은 CascadeType.ALL로 설정되어 있으므로, User 엔티티의 상태가 변경될 때 연관된 Post 엔티티들의 상태도 함께 변경됩니다.


    따라서 이 코드를 실행하게 되면,

    User user = new User();
    Post post1 = new Post();
    Post post2 = new Post();
      
    post1.setUser(user);
    post2.setUser(user);
      
    user.getPosts().add(post1);
    user.getPosts().add(post2);
      
    entityManager.persist(user);
      
    

    User 엔티티와 연관된 Post 엔티티들도 함께 저장됩니다. 그리고 User 엔티티를 삭제하면 연관된 Post 엔티티들도 함께 삭제됩니다.

    • persist() 메서드는 엔티티를 영속화(persistent)하는 메서드입니다. 즉, 새로운 엔티티를 데이터베이스에 저장하거나, 이미 있는 엔티티를 가져와서 영속성 컨텍스트(persistence context)에 추가하는 작업을 수행합니다.

      • 영속성 컨텍스트?

        영속성 컨텍스트(persistence context)는 JPA가 엔티티를 관리하는 논리적인 영역입니다. 즉, 엔티티 매니저(entity manager)가 관리하는 엔티티 객체들이 영속성 컨텍스트 내부에서 관리됩니다.

        영속성 컨텍스트는 엔티티를 데이터베이스에 저장하거나, 조회, 수정, 삭제 등의 작업을 수행할 때 사용됩니다. 영속성 컨텍스트는 엔티티 매니저를 통해 생성되고, 엔티티 매니저가 소멸될 때 함께 소멸됩니다.

        영속성 컨텍스트는 다음과 같은 주요한 특징을 갖습니다.

        • 엔티티의 생명주기를 관리합니다.
        • 1차 캐시(First-Level Cache)를 제공합니다. 같은 엔티티가 여러 번 조회될 때 캐시에서 가져오기 때문에, 데이터베이스에 매번 접근하지 않아도 됩니다.
        • Dirty Checking 기능을 제공합니다. 엔티티가 변경되었는지 여부를 판단하여 변경이 감지되면 자동으로 UPDATE 쿼리를 실행합니다.
        • 트랜잭션을 지원합니다. 트랜잭션을 시작하면 영속성 컨텍스트가 시작되고, 트랜잭션을 커밋하거나 롤백하면 영속성 컨텍스트도 함께 종료됩니다.
  • aaa

댓글남기기