Dependency (의존) ?

A가 B에 의존하고 있는 상태일 때, B에 변화가 일어나면 그 변화가 A에도 영향을 미치는 것

 

class Chef {
    private Recipe recipe = new Recipe();

    public Chef() {
       this.recipe.cook();
    }
}

 

흔히 드는 예시 중 하나

요리사는 레시피에 의존

따라서 레시피가 바뀌면 요리사의 행위도 변화

 

Chef 객체는 Recipe객체를 생성하고, 그 객체가 가지고 있는 cook이라는 메소드를 활용

만약 Recipe가 하나가 아니라 여러개가 존재하고, Recipe를 추가, 수정, 삭제하고 싶다면 해당하는 객체에 대한 코드를 추가, 수정, 삭제 필요

 

>> 코드 결합도가 높아지게 되어 코드 재활용성 등 문제 발생

의존성 주입을 사용하는 이유

 

Dependency Injection 사용

public class Recipe {...}
public class Pizza extends Recipe{...}
public class Chicken extends Recipe {...}

class Chef {
    private Recipe recipe = new Recipe();

    public Chef(Recipe recipe) {
       this.recipe = recipe;
    }
    
    public startCook(){
    	this.recipe.cook();
    }
}

Chef 객체에 Recipe라는 객체를 주입해서 사용

Pizza, Chicken 등 다른 레시피를 요리하고 싶다면 해당 요리의 객체를 Chef객체에 넘겨주어 생성

하나의 코드를 계속해서 재사용 가능

 

 

DI의 장점

1. 코드의 재활용성 증가

2. 객체 사이의 의존성/종속성 감소

3. 가독성 증대

4. Test 용이

 

 

 

Spirng에서의 DI

Spring은 DI를 편하게 사용하는 방법 3가지 제공

 

1. 생성자 주입

Contstructor Injection

@Service
public class UserServiceImpl implements UserService{
    private UserRepository userRepository;
    private UserServiceImpl userService;

    @Autowired
    public UserServiceImpl(UserRepository userRepository, UserService userService){
        this.userRepository = userRepository;
        this.userServicer = userService;
    }
}

생성자 주입은 생성자 호출 시점에 1번 호출 되는것이 보장

주입받는 객체의 변화가 없거나 반드시 객체의 주입이 필요한 경우에 강제하기 위해 사용 가능

 

** Spring에서는 생성자가 1개만 있을 경우 @Autowired는 생략 가능

 

 

2. 수정자 주입

Setter Injection

Setter를 사용해서 의존 관계를 주입하는 방법

주입 객체가 변할 수 있는 경우에 사용

@Service
public class UserServiceImpl implements UserService{
    private UserRepository userRepository;
    private UserServiceImpl userService;

    @Autowired
    public void setUserRepository(UserRepository userRepository){
        this.userRepository = userRepository;
    }
    
    @Autowired
    public void setmUserService(UserService userService){
        this.userService = userService;
    }
}

@Autowired로 주입 대상이 없는 경우에는 오류 발생 >> Bean에 존재하지 않는 경우

 

 

3. 필드 주입

Feild Injection

필드에 의존 관계를 주입하는 방법

@Service
public class UserServiceImpl implements UserService{
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private UserServiceImpl userService;
    
}

코드가 간결하기 때문에 과거에 많이 사용되던 방법 

But 외부에서 변경이 불가능 >> Test코드에서 Mock데이터를 사용하여 주입 불가

 

Spring과 같은 DI프레임워크가 존재해야만 사용 가능

 

 

 

생성자 주입을 권장하는 이유

  • 객체의 불변성 확보
  • Test코드의 작성
  • final키워드 작성 및 Lombok 결합

DI를 위한 3가지 방법 중 생성자 주입만이 객체 생성과 동시에 의존성 주입 >> final 변수 할당 가능 !!

나머지 방법은 객체를 우선 생성 => 의존성 주입 함수 호출 

순서로 수행되기 때문에 finla 변수 할당 불가능

 

  • 순환참조에러 방지

클라이언트 구동 시, Bean에 등록하기 위해 객체를 생성하는데, 이때 순환참조 발견 시 바로 에러 호출

만약 수정자 주입을 사용한다면 객체 생성 후, 객체에 의존성을 주입하는 순간에 에러 호출되기 때문에 생성만 한 상태에서는 코드가 잘못되었는지 발견하기 힘듬

 

 

'끄적 > BE' 카테고리의 다른 글

MVC1 MVC2  (0) 2023.01.05
Inversion of Control (제어 반전)  (0) 2023.01.03
Persistence Context (영속성 컨텍스트)  (0) 2023.01.01
Spring MVC  (0) 2022.12.29
JPA, Spring Data Jpa  (0) 2022.12.28

영속성 컨텍스트?

Entity를 영구 저장하는 환경

어플리케이션과 DB 사이에서 객체를 보관하는 가상의 DB같은 역할

서비스별로 EntityManager Factory 존재

Entity Manager Factory에서 DB접근 트랜잭션 발생시마다 스렏르별로 EntityManager를 생성하여 영속성 컨텍스트에 접근

EntityManager를 통해 Entity저장, 조회 시 영속성 컨텍스트에 Entity 보관하고 관리

영속성 컨텍스트는 EntityManager를 생성할 때 생성

 

em.persist(entity);

 

** Spring에서는 EntityManager를 주입하여 사용하면 같은 트랜잭션의 범위에 있는 EntityManager는 같은 영속성 컨텍스트에 접근 **

 

 

EntityManager

영속성 컨텍스트 내에서 Entity를 관리

JPA에서 제공하는 interface로 Spring bean으로 등록되어 @AutoWired로 사용 가능

@Autowired
private EntityManager em;

 

 

 

Entity 생명주기

 

new / trasient

비영속

영속성 컨텍스트와 관계 없는 상태

Entity 객체를 생성했지만, 아직 영속성 컨텍스트에 저장하지 않은 상태

User user = new User();

 

 

managed

영속

영속성 컨텍스트에 저장된 상태

Entity가 영속성 컨텍스트에 의해 관리됨

영속 상태라고 바로 DB에 값이 저장되지 않고 트랜잭션 커밋 시점에 영속성 컨텍스트에 있는 정보를 DB에 쿼리로 전달

@Autowired
private EntityManager entityManager;

    User user = new User();
    entityManager.persist(user);

 

 

detached

준영속

영속성 컨텍스트에 저장되었다가 분리된 상태

Entity를 준영속 상태로 만들기 위해서는 entityManager.detach() 호출

// managed to detached
entityManager.detach(user);

// 영속성 컨텍스트 비우기
// 영속성 컨텍스트를 비우면 관리되고 있던 Entity들은 준영속 상태로 변경
// 대기 상태에 있던 변경 데이터도 삭제
entityManager.clear();

// 영속성 컨텍스트 종료
// 커밋 이전에 영속성 컨텍스트를 종료하면 관리되던 Entity들은 준영속 상태로 변경
entityManager.close();

// detached to managed
// detached 상태의 Entity를 merge하면 다시 영속상태로 전환
entityManager.merge(user);

- 1차 캐시, 쓰기 지연, 변경 감지, 지연 로딩을 포함한 영속성 컨텍스트가 제공하는 어떤 기능도 동작 X

- 식별자 값 존재

 

 

removed

삭제

영속성 컨텍스트와 DB에서 해당 Entity를 삭제한 상태

entityManager.remove(user);

 

 

 

영속성 컨텍스트의 특징

Entity를 식별자 값 (@Id로 테이블 PK와 매핑한 값)으로 구분

영속 상태는 식별자 값이 반드시 존재

식별자 값 없을 시 예외 발생

 

JPA는 보통 트랜잭션 커밋하는 순간 영속성 컨텍스트에 새로 저장된 Entity를 DB에 반영

flush

 

1차 캐시

영속성 컨텍스트는 내부에 캐시를 가지고 있음

영속 상태의 Entity는 모두 이곳에 저장

 

** 영속성 컨텍스트 내부의 Map 존재

Key : @Id 매핑한 값

Value : Entity 인스턴스

 

조회 과정

Member member = em.find(Member.class, "member1");

1. 1차 캐시에서 Entity검색

2. 존재하면? >> 메모리에 있는 1차 캐시에서 Entity 조회

3. 존재하지 않으면? >> DB에서 조회

4. 조회한 데이터로 Entity 생성해 1차 캐시에 저장 (Entity를 영속 상태로)

5. 조회한 Entity 리턴

 

 

** 1차 캐시에서 조회

 

 

** DB에서 조회

 

 

 

동일성 보장

영속성 컨텍스트는 Entity의 동일성을 보장

Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");
System.out.print(a==b) // true

동일성 비교 : 실제 인스턴스가 같다. ==을 사용해 비교한다.
동등성 비교 : 실제 인스턴스는 다를 수 있지만 인스턴스가 가지고 있는 값이 같다. equals()메소드를 구현해서 비교한다.

 

EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();

// 엔티티 매니저는 데이터 변경 시 트랜잭션을 시작해야 한다.
transaction.begin();    // 트랜잭션 시작

em.persist(memberA);
em.persist(memberB);
// 여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.

// 커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit();   // 트랜잭션 커밋

 

Transactional Write-Behind (트랜잭션을 지원하는 쓰기 지연)

EntityManager는 트랜잭션을 커밋하기 직전까지 내부 쿼리 저장소에 SQL 임시 저장

트랜잭션 커밋할 때 모아둔 쿼리를 DB로 전송

이것을 "트랜잭션 지원하는 쓰기 지연" 이라고 함

 

쓰기 지연, 회원 A 영속

 

 

쓰기 지연, 회원 B 영속

 

 

트랜잭션 커밋, flush, 동기화

 

 

1. 트랜잭션 커밋

2. EntityManager >> 영속성 컨텍스트 flush

3. DB 동기화 >> 등록, 수정, 삭제한 Entity를 DB 반영

** 쓰기 지연 SQL저장소에 모인 쿼리를 DB로 전달

4. 실제 DB 트랜잭션 커밋

 

 

 

변경 감지

 

1. 트랜잭션 커밋 시, EntityManager 내부에서 먼저 flush 호출

2. Entity와 스냅샷 비교하여 변경된 Entity탐색

3. 변경된 Entity가 있으면 수정 쿼리를 생성해서 쓰기 지연 SQL저장소에 저장

4. 쓰기 지연 저장소의 SQL flush

5. 실제 DB에 트랜잭션 커밋

 

 

 

 

업데이트 기본 전략

JPA의 기본 전략은 모든 필드를 업데이트

- 수정쿼리가 같고

- 동일 쿼리 보내면 DB는 이전에 파싱된 쿼리를 재사용 할 수 있기 때문

 

** 필드가 너무 많거나 저장되는 내용이 크면??

Hiberante 확장 기능 사용

@Entity
@org.hibernate.annotation.DynamicUpdate
@Table(name = "Member")
public class Member {...}

수정된 데이터만 사용해서 동적으로 udate SQL 생성

 

 

엔티티 삭제

Entity 즉시 삭제 X

삭제 쿼리를 쓰기 지연 SQL저장소에 저장

em.remove() 호출 시, 영속성 컨텍스트에서 제거

 

 

플러시

영속성 컨텍스트의 변경 내용을 DB에 반영

영속성 컨텍스트의 Entity를 지우는게 아니라, 변경 내용을 DB에 동기화 하는것

 

1. 변경 감지 동작, 스냅샷과 비교해서 수정된 Entity 탐색

2. 수정된 Entity에 대해 수정 쿼리를 만들고 쓰기 지연 SQL 저장소에 저장

3. 쓰기 지연 SQL저장소의 쿼리를 DB에 전달

 

flush 방법

- em.flush() 호출

거의 사용 X

테스트, JPA와 타 프레임워크 중복 사용할 때 주로 사용

 

- 트랜잭션 커밋 시 자동 호출

 

- JPQL 쿼리 실행 시 자동 호출

em.persist(memberA);
em.persist(memberB);
em.persist(memberC);

// 중간에 조회
query = em.createQuery("select m from Member m", Member.class);
List<Member> members = query.getResultList();

Entity가 DB에 반영되지 않고 영속성 컨텍스트에만 존재할 때 조회 실행 하는 경우가 있으므로

JPQL 실행 시에 flush를 자동 호출하여 영속성 컨텍스트의 데이터를 DB에 반영한 후, 조회 실행

 

'끄적 > BE' 카테고리의 다른 글

Inversion of Control (제어 반전)  (0) 2023.01.03
Dependency Injection (의존성 주입)  (0) 2023.01.03
Spring MVC  (0) 2022.12.29
JPA, Spring Data Jpa  (0) 2022.12.28
JPA  (0) 2022.12.28

MVC란?

Model, View, Controller 로 구성

소프트웨어가 서비스하는 방식에 대한 패턴을 지칭

!! 프레임워크/라이브러리가 아님 !!

 

MVC 특징

소프트웨어 서비스를 위한 여러 과정과 처리를 기능 단위 별로 나눠서 작성하여 코드 가독성 증대

 

Model

데이터와 비즈니스 로직을 관리

어플리케이션이 포함해야 될 데이터가 무엇인지 정의

Java Beans

Dao, Dto, Service 등

 

View

컨트롤러와 소통

레이아웃과 화면 처리

어플리케이션의 데이터를 보여주는 방식 정의

JSP, Thymeleaf, Groovy 등 여러 템플릿 엔진 존재

Html, JSP, Json 등

 

Controller

View에서 액션, 이벤트에 대한 input 처리

Model에게 데이터 전달하기 전 가공 가능

View와 Model 사이의 인터페이스 역할

어플리케이션 사용자의 입력에 대한 응답으로 Model 및 View를 업데이트하는 로직 포함

Model, View에 대한 사용자 입력/요청을 수신하여 그에 따라 적절하나 결과를 Model에 담아 View에 전달

Model Object와 이 Model을 화면에 출력할 View Name 반환

Controller -> Service -> Dao -> DB

 

 

 

Spring MVC 란?

 

Spring에서 MVC패턴을 구성하고 구성요소들을 확장할 수 있게 만든 도구

 

 

Spring MVC 구조

주요 구성요소는 Model, View, Controller 이지만, 이들이 유기적으로 동작하기 위한 다양한 구성요소가 포함

 

  • DispatcherServlet(Front Controller)
  • Handler(Controller)
  • ModelAndView
  • ViewResolver

 

 

Spring MVC 동작 과정

 

1. 사용자 요청(HTTP Request)을  DispatcherServlet이 FrontController로써 받음

2. HandlerMapping에게 Controller 선택 위임

3-1. HanlerMapping은 사용자의 요청 경로를 이용해 처리할 Controller객체를 찾아 DispatcherServlet에 리턴

3-2. DispatcherServlet은 @Controller 어노테이션을 사용해서 구현한 Controller

       HttpRequestHandler 인터페이스를 구현한 Contorller클래스를 실행 후 ControllerAdapter(HandlerAdapter)객체에 요청 처리 위임

4. ControllerAdapter(HandlerAdapter)객체는 Controller의 알맞은 메소드를 호출, Service의 동작 수행

5. Service수행 결과 Controller에 리턴

6-1. ControllerAdapter(HandlerAdapter)에게 결과 전달

6-2. ControllerAdapter(HandlerAdapter)는 리턴받은 객체를 ModelAndView객체에 담아 DispatcherServlet에 전달

7. ViewResolver에게 ModelAndView객체를 전달

8. ViewResolver는 ModelAndView객체에 담긴 View Name을 이용해서 View 객체를 찾거나 생성하여 리턴

     DispatcherServlet이 ViewResolver가 리턴한 View 객체에게 응답 결과 생성 요청

9.  View객체가 사용자에게 전송할 응답 결과 생성 (JSP 사용하는 경우 View객체는 JSP실행)

     ModelAndView 의 Model 객체에 담겨 있는 데이터가 응답 결과에 필요하면 Model 에서 데이터를 꺼내 JSP 에서 사용할 수 있다.

 

 

DispatcherServlet

제일 앞단에서 HTTP Request를 처리하는 Controller

Dispatcher (보내다) 라는 뜻에 알맞게 HTTP Request로 들어오는 요청을 가장 먼저 받아 적합한 Controller에 전달해주는 Front Controller 

 

 

Handler(Controller)

HTTP Request를 처리해 Model을 만들고 View 지정

DispatcherServlet 에 의해 배정된 Controller는 HTTP Request를 처리하고, HTTP Request 처리해 필요한 데이터를 Model에 저장

HTTP Request에 따라 HTTP가 보여줄 View Name을 지정

View Name 뿐만 아니라 View를 직접 리턴 가능

 

 

ModelAndView

Model :  Map 자료구조를 사용

데이터를 Key-Value 쌍으로 만들어 저장

 

ModelAndView객체는 모델과 같은 동작을 수행

 

	@GetMapping("/test2")
	public String getTest2(Model model) {
		
		SampleVO vo = new SampleVO();
		vo.setId(0);
		vo.setName("name");
		
		model.addAttribute("value" , vo);
		
		return "test2";
		
	}

 // 결과
test2.jsp 
id:<c:out value="${value.id}"/>
	<br/>
name:<c:out value="${value.name}"/>

Model 사용

Model의 Attribute로 Value 라는 Key, vo 라는 Value를 설정해서 test2 String으로 리턴

 

@GetMapping("/test2")
	public ModelAndView getTest2(ModelAndView modelAndView) {
		
		SampleVO vo = new SampleVO();
		vo.setId(0);
		vo.setName("name");
		
		modelAndView.addObject("value", vo);
		modelAndView.setViewName("test2");
		
		return modelAndView;
		
	}

// 결과
test2.jsp 
id:<c:out value="${value.id}"/>
	<br/>
name:<c:out value="${value.name}"/>

ModelAndView객체 사용

addObject로 Key : value, Value : vo 값 저장

setViewName 으로 test2 String 저장

ModelAndView객체 자체를 리턴

 

 

 

ViewResolver

어떤 View를 사용할 것인지 설정하는 역할

예를 들어 데이터를 API형태로 제공하길 원한다면 ViewResolver를 통해 Json형태로 전달 가능

** Thymeleaf, Velocity, FreeMarker, JSP, JsonView 등의 View를 골라 설정

 

 

 

 

 

1.
핸들러 조회 : 핸들러 매핑을 통해 URL에 매핑된 핸들러(컨트롤러) 조회
2.
핸들러 어댑터 조회: 핸들러를 실행할 수 있는 핸들러 어댑터 조회
3.
핸들러 어댑터 실행: 핸들러 어댑터 실행
4.
핸들러 실행: 핸들러 어댑터가 실제 핸들러를 실행
5.
ModelAndView 반환: 핸들러 어댑터는 핸들러가 반환하는 정보를 ModelAndView로 변환해 반환.
6.
viewResolver 호출: 뷰 리졸버를 찾아 실행한다.
⇒ JSP: InternalResourceViewResolver가 자등 등록되어 사용된다.
7.
View 반환: 뷰 리졸버는 뷰의 논리 이름을 물이 이름으로 바꾸고 렌더링 역할을 담당하는 뷰 객체 반환.
⇒ JSP: InternalResourceView(JstlView)를 반환하는데, 내부에는 forward() 가 있다.
8.
뷰 렌더링: 뷰를 통해서 뷰를 렌더링한다.

'끄적 > BE' 카테고리의 다른 글

Dependency Injection (의존성 주입)  (0) 2023.01.03
Persistence Context (영속성 컨텍스트)  (0) 2023.01.01
JPA, Spring Data Jpa  (0) 2022.12.28
JPA  (0) 2022.12.28
Token을 사용한 로그인 인증  (0) 2022.12.28

JPA 핵심 : Persistence 클래스

 

EntityManager에서 제공하는 API 사용

 

ex)

@Repository
@RequiredArgsConstructor
public class OrderRepository {

    private final EntityManager em;

    public void save(Order order){
        em.persist(order);
    }

    public Order findOne(Long id){
        return em.find(Order.class, id);
    }

    public List<Order> findAll() {
        return em.createQuery("select o from Order o", Order.class)
                .getResultList();
    }
    
    public List<Order> findAllWithItem() {
        return em.createQuery(
                "select distinct o from Order o" +
                        " join fetch o.member m" +
                        " join fetch o.delivery d" +
                        " join fetch o.orderItems oi" +
                        " join fetch oi.item i", Order.class)
                .getResultList();
    }
}

 

위의 OrderRepository는 Spring Data Jpa가 제공하는 JpaRepository를 상속하지 않고 

@Repository만 활용하여 EntityManager가 제공하는 API를 활용하여 CRUD 구현

 

 

Hibernate ??

JPA의 구현체 중 하나

 

 

Hibernate의 SessionFactory, Session, Transaction 을 살펴보면, 

JPA 인터페이스인 EntityManagerFactory, EntityManager, EntityTransaction을 상속받아 구현되어 있음

 

 

 

 

 

Spring Data Jpa

Spring에서 제공하는 모듈 중 하나

개발자가 JPA를 더 쉽고 편하게 사용할 수 있도록 도와주는 라이브러리

JPA를 추상화 시킨 Repository 인터페이스를 제공하여 개발자가 JPA를 더 편하게 사용할 수 있게 하는 모듈

사용자가 Repository 인터페이스에 정해진 규칙대로 메소드 입력 시,

Spring이 알아서 해당 메소드 이름에 적합한 쿼리를 날리는 구현체를 만들어 Bean 으로 등록

 

Spring Data Jpa 사용하지 않는다면, 클래스에 @Repository 어노테이션 작성, EntityManager의 API를 직접 호출해야 함

 

Spring Data Jpa 사용 시, JpaRepository 인터페이스를 상속받아 메소드 명으로만 CRUD 구현 가능

 

 

JpaRepository 메소드 작성 예시

public interface AccountRepository extends JpaRepository<Account, Long> {

    boolean existsByUsername(String username);

    Optional<Account> findById(Long id);

    Optional<Account> findByUsername(String username);

    Optional<Account> findByUsernameAndPassword(String username, String password);
}

 

Repository 인터페이스에 정해진 규칙대로 메소드 입력 시, 해당 메소드에 적합한 JPQL 생성해 처리

 

** 상세한 메소드 명명규칙 참고

https://docs.spring.io/spring-data/jpa/docs/1.10.1.RELEASE/reference/html/#jpa.sample-app.finders.strategies

 

Spring Data JPA - Reference Documentation

Example 11. Repository definitions using Domain Classes with mixed Annotations interface JpaPersonRepository extends Repository { … } interface MongoDBPersonRepository extends Repository { … } @Entity @Document public class Person { … } This example

docs.spring.io

https://docs.spring.io/spring-data/jpa/docs/2.4.3/reference/html/#jpa.query-methods.query-creation

 

Spring Data JPA - Reference Documentation

Example 109. Using @Transactional at query methods @Transactional(readOnly = true) public interface UserRepository extends JpaRepository { List findByLastname(String lastname); @Modifying @Transactional @Query("delete from User u where u.active = false") v

docs.spring.io

 

 

 

 

------------------------------------------------------------------------------------------------------------------------------

 

요약하자면

Jpa 활용하기 위해서는 Persistence 의 API (EntityManager), Hibernate와 같은 구현체 활용

 

Spring Data Jpa는 Jpa를 사용하기 쉽게 미리 구현된 인터페이스 (JpaRepository)를 제공

JpaRepository 상속받은 클래스는 메소드 명으로 CRUD 구현 가능

 

'끄적 > BE' 카테고리의 다른 글

Persistence Context (영속성 컨텍스트)  (0) 2023.01.01
Spring MVC  (0) 2022.12.29
JPA  (0) 2022.12.28
Token을 사용한 로그인 인증  (0) 2022.12.28
JWT  (0) 2022.12.28

** spring data jpa 에 관한 설명은 아래 링크 **

https://rainover0824.tistory.com/38

 

JPA, Spring Data Jpa

JPA 핵심 : Persistence 클래스 EntityManager에서 제공하는 API 사용 ex) @Repository @RequiredArgsConstructor public class OrderRepository { private final EntityManager em; public void save(Order order){ em.persist(order); } public Order findOne(

rainover0824.tistory.com

 

 

JPA란?

Java Persistence API 

 

자바 진영에서 ORM 기술 표준으로 사용되는 인터페이스의 모음

어플리케이션과 JDBC 사이에서 동작

 

 

 

 

 

 

ORM?

자바의 객체와 RDB를 매핑

DB의 특정 테이블이 자바 객체로 매핑되어 SQL을 하나하나 작성하지 않고 객체로 구현 가능

어플리케이션의 객체를 RDB 테이블에 자동으로 영속화 해주는 기술

 

 

장점

  • SQL문이 아닌 Method를 통해 DB 조작 가능, 개발자가 객체 모델을 이요하여 로직 구성하는데 집중 가능
  • Query와 같이 필요한 선언문, 할당 등의 부수적 코드 필요 X
  • 객체지향적인 코드 작성 가능 >> 생산성 증가
  • 매핑 정보가 Class로 명시되어있기 때문에 ERD 의존도 낮고 유지보수, 리팩토링에 유리
  • Ex) DB를 변경하는 경우 ORM 사용한다면 쿼리 수정할 필요 X

 

단점

  • 프로젝트 규모가 크고 복잡한 설계일 경우 속도 저하, 일관성을 무너뜨리는 문제가 생길 수 있음
  • 복잡하고 무거운 Query는 속도를 위해 별도 튜닝이 필요, 따라서 결국 SQL을 사용해야 할 수 도 있음

 

 

 

JPA 사용하는 이유?

JPA가 알아서 반복적인 CRUD SQL을 처리

매핑된 관계를 이용해서 SQL을 생성하고 실행

SQL 사용이 필요해지는 경우 Native SQL이라는 기능을 통해 직접 SQL작성도 가능

 

SQL이 아닌 객체 중심으로 개발할 수 있다는 것이 가장 큰 장점

생산성, 유지보수성 증대

 

 

JPA 동작과정

JPA는 어플리케이션과 JDBC 사이에서 동작

개발자가 JPA를 사용하면 JPA내부에서 JDBC API를 사용하여 SQL 호출, DB와 통신

개발자가 직접 JDBC API를 사용 X

 

 

JPA 저장

1. DB에 저장하고 싶은 데이터를 담고 있는 객체를 (ex. 회원 정보를 담고있는 member 객체 같은) JPA에 전달

2. JPA는 객체를 분석, Insert SQL 생성

3. JDBC API 사용하여 SQL을 DB에 전달 

 

 

JPA 조회

1. 조회하고자 하는 객체의 PK값을 JPA에 전달

2. JPA가 엔티티 매핑 정보(@Entity) 를 바탕으로 select SQL 생성

3. JDBC API 사용하여 SQL DB에 전달

4. DB로부터 결과를 전달받고, 전달받은 결과를 객체에 매핑

 

 

 

JPA 수정

 

JPA는 수정 메소드 제공 X

1. 위의 조회 기능을 사용해서 매핑된 객체에 조회된 정보를 담은 후, 매핑된 객체에서 변경하고자 하는 값을 변경

2. 커밋하게 되면 DB에 update SQL 전달

3. 변경된 값 DB 반영

 

** Spring 에서 사용하는 JPA는 JPA를 이용하는 spring-datat-jpa 프레임워크!!

JPA와는 다름

'끄적 > BE' 카테고리의 다른 글

Persistence Context (영속성 컨텍스트)  (0) 2023.01.01
Spring MVC  (0) 2022.12.29
JPA, Spring Data Jpa  (0) 2022.12.28
Token을 사용한 로그인 인증  (0) 2022.12.28
JWT  (0) 2022.12.28

Access Token 방식

 

1. 사용자 로그인

2. 서버 측에서 계정 정보 확인 (Id, Password 등)

3-1. 사용자의 고유한 Id값 부여 후 Payload에 정보 삽입

3-2. JWT토큰의 유효기간 설정

4. secret key 를 통해 암호화된 Access Token을 HTTP 응답 헤더로 전송

5. 사용자는 인증이 필요한 요청마다 가지고 있는 Access Token을 HTTP 요청 헤더로 전송

6. 서버 측에서 해당 ㅗ큰의 Verify Signature를 secret key로 복호화 후, 조작 여부, 유효 기간 확인

7. 검증이 완료된다면 Payload 디코딩하여 사용자 Id에 맞는 데이터 전송

 

 

왜 사용할까?

서버 확장 시, 세션, 쿠키를 사용한 인증 방식의 경우 분산된 시스템 설계 필요 >> 설계 과정이 복잡

클라이언트 측에서 인증 정보를 가지고 있기 때문에 세션, 쿠키를 이용한 인증과는 달리 별도의 저장소 관리가 필요 없음 

따라서 서버 확장성 용이

 

 

Access Token + Refresh Token 방식

Access Token을 이용한 인증 방식의 경우, 클라이언트에서 인증 정보를 관리

보안 관점에서 토큰 탈취에 취약

 

이를 해결하기 위해 Access Token의 유효기간을 짧게 설정하고

Refresh Token을 따로 발급하여 Access Token 이 만료 되었을 때 새로운 Access Token을 발급받기 위한 정보로 활용

 

 

 

 

++ 위의 Access Token 만 활용한 응답 방식에서 요청 만료 시, 

 

1. 서버 측에서 Access Token 만료 확인

2. Access Token 만료 응답

3. 만료 응답 받은 사용자는 Access Token, Refresh Token 을 활용하여 Access Token 신규 발급 요청

4. 서버측에서 Refresh Token 확인 후 새로운 Access Token 발급하여 응답

 

이 과정이 추가

 

 

 

'끄적 > BE' 카테고리의 다른 글

Persistence Context (영속성 컨텍스트)  (0) 2023.01.01
Spring MVC  (0) 2022.12.29
JPA, Spring Data Jpa  (0) 2022.12.28
JPA  (0) 2022.12.28
JWT  (0) 2022.12.28

Jason Web Token

Json 포맷을 이용하여 사용자에 대한 속성을 전달하는 Claim 기반 Web Token

토큰 자체를 정보로 사용하는 Self-Contained 방식으로 정보를 안전하게 전달

 

JWT구조

Header, Payload, Signature  3부분으로 구성

Json 형태인 각 부분은 Base64Url로 인코딩

각 부분을 이어주기 위해 , 구분자 사용

 

 

Header

alg

Signature를 해싱하기 위한 알고리즘을 지정

 

typ

토큰의 타입을 지정

ex) JWT

{ 
   "alg": "HS256",
   "typ": JWT
 }

 

 

 

Payload

토큰에 담을 정보

하나의 정보 조각을 클레임(Claim) 이라고 부르고 이는 name, value 한 쌍으로 이루어 짐

 

클레임의 종류는 크게 3개로 구분

 

register : 등록된 클레임

서비스에 필요한 정보들이 아닌, 토큰에 대한 정보를 담기 위해 이름이 이미 정해진 클레임

등록된 클레임은 모두 선택적 (Optional)

 

  • iss : 토큰 발급자 (Issuser)
  • sub : 토큰 제목 (subject)
  • aud : 토큰 대상자 (audience)
  • exp : 토큰 만료 시간 (expiration)
  • nbf : (not before) 토큰의 활성 날짜와 비슷한 개념, 이 날짜가 지나기 전까진 토큰 처리 X
  • iat : 토큰이 발급된 시간 (issued), 이 값을 활용하여 토큰의 age가 얼마나 되었는지 판단 가능
  • jti : JWT의 고유 식별자, 주로 중복적인 처리 방지를 위해 사용, 일회용 토큰에 사용 시 유용

 

public : 공개된 클레임

공개 클레임들은 충돌이 방지된 (collision-resistant) 이름을 가지고 있어야 함

충돌 방지를 위한 URI 형식의 이름

 

{
    "https://rainover0824.tistory.com//jwt_claims/is_admin": true
}

 

private : 비공개 클레임

서버와 클라이언트 협의 하에 사용되는 클레임 이름

공개 클레임과는 달리 이름이 중복되어 충돌 가능성 존재

 

{
    "username": "rainover"
}

 

 

 

Payload 예시

{
    "iss": "tistory.com",
    "exp": "1485270000000",
    "https://rainover0824.tistory.com/jwt_claims/is_admin": true,
    "userId": "11028373727102",
    "username": "rainover"
}

 

 

Signature (서명)

헤더의 인코딩 값, 정보의 인코딩 값을 합친 후 주어진 비밀키로 해쉬하여 생성

 

** 서명 부분을 만드는 슈도 코드의 구조

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

 

문자열을 Base64 형태로 표현

 

 

 

 

JWT 예시

 

앞서 설명한 Header, Payload, Signature 을 합치면

 

이런 JWT 생성!

 

'끄적 > BE' 카테고리의 다른 글

Persistence Context (영속성 컨텍스트)  (0) 2023.01.01
Spring MVC  (0) 2022.12.29
JPA, Spring Data Jpa  (0) 2022.12.28
JPA  (0) 2022.12.28
Token을 사용한 로그인 인증  (0) 2022.12.28

+ Recent posts