1. @Id와 함께 쓰여서, PK 값을 자동으로 생성하도록 지정
  2. 전략(strategy) 을 통해 어떤 방식으로 값이 만들어질지 정할 수 있음
  3. 특징
    1. PK값 자동 생성
  4. 장점
    1. 개발자가 일일이 PK 값 넣지 않아도 됨
  5. 단점
    1. 전략에 따라 성능 / 호환성 차이 있음
      1. IDENTITY는 insert 후에만 PK 알 수 있어서 JPA 배치 처리에 제약
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)

AUTO : JPA가 DB 방언에 맞게 자동 선택

IDENTITY : DB의 Auto Increment 기능 사용 (MYSQL 등)

  1. 과정

    1. 개발자가 persist 호출
    User u = new User("민상");
    em.persist(u);
    
    1. JPA → DB insert SQL ㅡ즉시 실행
    
    JPA → DB insert SQL 즉시 실행
    
    insert into user (username) values ('민상');
    
    DB가 PK 값 생성 (AUTO_INCREMENT)
    
    예: id = 1
    
    
    1. DB가 PK값 생성

    id = 1

    1. JPA 가 DB 에서 생성된 PK를 다시 조회해서 엔티티에 채워넣음
    u.getId(); // 1
    

SEQUENCE : DB의 시퀀스 오브젝트 사용 (Oracle, PostgreSQL 등)

TABLE : 별도 키 생성용 테이블을 만들어서 관리

  1. SWQUENCE 방식

    1. 특징

      1. DB에서 제공하는 시퀀스 오브젝트(CREATE SEQUENCE …)를 통해 PK를 insert 전에 미리 가져옴
      2. JPA가 persist() 호출 시 DB에 select nextval(…) 실행 → 엔티티의 id 필드에 바로 세팅
      3. insert는 나중에 트랜잭션 flush나 commit 시점에 모아서 실행 가능
    2. 장점

      1. 배치 처리 유리
        1. 미리 pk 값을 알 수 있으니까 insert 쿼리를 한 번에 모아서 실행 가능(JDBC batch insert)
      2. 고유성 보장
        1. DB가 알아서 중복 없는 연속적인 번호를 생성해줌
      3. 트랜잭션 충돌 방지
        1. 동시에 여러 요청이 와도 시퀀스가 알아서 각기 다른 값을 줌(위에서 아래로 순서대로 값을 넣어주니까)
    3. 단점

      1. DB 종속적
        1. MySQL은 시퀀스를 지원하지 않음 → Oracle, PostgreSQL, H2 같은 DB에서만 가능
      2. 추가 SELECT 필요
        1. persist 시점에 select nextval 퀴리를 날려야 함 → 성능 상 오버헤드가 발생함
      3. allocationSize 주의
        1. @SequenceGenerator 에서 allocationSIze 를 크게 잡으면 성능은 좋아지지만, DB와 JPA의 시퀀스 값이 어긋날 수 있음
      @Entity
      public class User {
          @Id
          @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_seq_gen")
          @SequenceGenerator(
              name = "user_seq_gen",          // JPA에서 부를 이름
              sequenceName = "user_seq",      // 실제 DB 시퀀스 이름
              allocationSize = 1              // 증가 단위
          )
          private Long id;
      
          private String username;
      
          public User() {}
          public User(String username) { this.username = username; }
      
          public Long getId() { return id; }
          public String getUsername() { return username; }
      }
      
  2. Spring Security+ JWT

    1. 회원가입

      1. Spring Security와 동일 ,DB + PasswordEncoder 사용
      2. 과정 특징
        1. Stateless 환경 호환 가능
        2. 장점
          1. 서버 확장성 용이
        3. 단점
          1. 토큰과 별도 DB 관리 필요
            1. JWT는 stateless 라 서버가 토큰을 저장하지 않습니다.
            2. 그래서 한번 발급된 토큰은 exp 정가지 게속 유효
            3. 사용자가 로그아웃을 했고나 계정이 해킹당했을 때 → 토큰을 강제로 막을 방법이 없음
            4. 해결책
              1. 블랙리스트 DB/Redis를 두고, 토큰 무효화 상태를 저장
              2. 요청 들어올 때마다 해당 토큰이 블랙리스트에 있는지 확인
            5. 리프레쉬 토큰 관리
            6. 보안 / 권한 변경 즉시 반영
    2. 로그인

      JwtTokenProvider
      
      @Component
      public class JwtTokenProvider{
      
      	private final String secretKey = "secret";
      	private final long validity = 3600000;
      	
      	public String createToken(String username, Collection<? extends GrantedAuthority> roles){
      		Claim claims = Jwts.claims().setSubject(username);
      		claims.put("roles", roles.stream().map(GrantedAuthority :: getAuthority).toList());
      		return Jwts.builder()
      							.setClaims(claims)
      							.setIssuedAt(new Date())
      							.setExpiration(new Date(System,currentTimeMillis() + validity))
      							.signWith(SignatureAlgorithm.HS256, secretKey.getBytes())
      							.compact();			
      	}
      	   public boolean validateToken(String token){ /* JWT 검증 */ }
      
          public String getUsername(String token){ /* JWT에서 사용자 조회 */ }
      
      }
      
      1. 메서드 특징
        1. 토큰 생성, 검증, 사용자 조회
        2. 장점
          1. Stateless, 서버 확장성 용이
        3. 단점
          1. 키 관리 필요, 탈취 시 위험
    3. JwtAUthenticationFilter

    @Component
    public class JwtAuthenticationFilter extends OncePerRequestFilter {
    	@Override
    	protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws ServletException, IOException{
    			String token = req.getHeader("Authorization");
    			if(token !=null && token. startsWith("Bearer ")){
    				token = token.substring(7);
    				if(jwtTokenProvider.validateToken(token)){
    				Stirng username = jwttokenProvider.getUsername(token);
    				UserDetails user = userDetailsService.loadUserByUsername(username);
    				SecurityContextHolder.getContext()
    															.setAuthentication(new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities()));}
    			
    			}
    			
    			chain.doFilter(req, res);
    	}
    
    }
    
    1. 필터 특징

      1. 요청마다 JWT 검증 → SecurityContext 세팅
      2. 장점
        1. API 친화적, Stateless
      3. 단점
        1. 모든 요청에서 필터 실행 →성능 고려 필요
    2. SecurityConfig

      @Bean
      SecurityFilterChain filterChain(HttpSecurity http, JwtAuthenticationFilter jwtFilter) throws Exception{
      	http.csrf(csrf -> csrf.disable())
      			.sessionManageMent(sm -> sm.sessionCreationPolicy(SessioncreationPolicy.STATELESS))
      			.authorizeHttpRequests(auth -> auth.requestMatchers("/auth/**").permitAll()
      			.anyRequest().authenticated())
      			.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
      }
      
  3. Spring Security + QAuth 2