개발 공부를 하면서 자주 들은 말들을 한번 쭉 정리해보고 싶은 마음이 생겨 글을 남기려고 한다.
데이터 무결성(Data Integrity)
데이터 값이 정확한 상태를 의미한다
데이터 정합성(Data Consistency) == 일관성
어떤 데이터들이 값이 서로 일치하는 상태를 의미한다.
ex) User Table, Product Table이 있다고 하자.
두 테이블에서 공통적으로 쓰이는 데이터에 대하여 서로 일치하면 -> 정합성
but, 데이터가 -1인데 이 데이터는 원래 양수여야 한다 => 무결성
멱등성(Idempotent)
연산을 여러 번 적용하더라도 결과가 달라지지 않는 성질, 연산을 여러 번 반복하여도 한 번만 수행된 것과 같은 성질
Q. 데이터를 Request 할 떄 변경되지 않은 값들도 줘야할까?
{
nickname : string // 닉네임 (10자 이내)
age : int // 연령대 (10, 20, 30, ...)
gender : char // 성별 ('M','W')
profileImage : string // 프로필 이미지
}
문득 DTO 설계를 하던 중 들었던 의문이다.
nickname만 수정을 했을 경우 age, gender, profileImage와 같은 다른 변수들도 같이 줘야하는게 맞을까?
API 설계를 저런 case 마다 하나하나 하면 상관없겠지만 보통은 그렇지 않다.
API의 일관성과 완결성을 유지하고 수정된 정보만 받는경우, 이전에 받았던 정보와 비교하여 어떤 정보가 변경되었는지 알기 어렵고 예기치 않은 오류가 발생할 수 있으므로 지양하는게 좋다고 함!
But, 운영을 하다가 뭔가 자주 일어나는 요청은 따로 patch로 빼면 좋을듯?
DTO vs VO vs Entity
DTO와 VO가 상당히 헷갈림...
REST API 설계
PathVariable로 쓰는경우는 뒤에 나올께 명확하게 나올 경우 쓰는게 좋음
/course/{courseId}
/like/course/{courseId}
like/{courseId}로 왜 하지 않았냐면 like뒤에 바로 값이 나오면 이를 나타내는 값이 뭔지 명확하지 않기 때문임!
RequestParam은 key-value이기 때문에 정렬이나 특정값을 명시해주고 싶을 때 사용하면 좋음
/comment/course/{courseId}?page={page}&sortby={sortby}
POST vs PUT vs PATCH
POST : 새로운 데이터를 추가할 때
PUT : 모든 데이터를 수정할 때
PATCH : 데이터의 일부를 수정할 때
예를 들어, PUT HTTP 메소드로 gildong 이라는 유저의 나이(age)를 15로 변경하고자 할때
수정된 값만 보낼 경우, 보내지 않은 데이터는 null로 변경되어 버린다.
PUT /users/1
{
"age": 15
}
HTTP/1.1 200 OK
{
"name": null,
"age": 15
}
따라서, PUT 요청 시에는 아래와 같이 변경되지 않는 데이터도 모두 전달해야한다.
PUT /users/1
{
"name": "gildong"
"age": 15
}
HTTP/1.1 200 OK
{
"name": "gildong",
"age": 15
}
그러나 PATCH를 이용하여 ‘age’만 변경하는 요청을 보내면,
새롭게 바뀐 부분만 반영되며 나머지는 기존의 데이터가 유지된다.
PATCH /users/1
{
"age": 15
}
HTTP/1.1 200 OK
{
"name": "gildong",
"age": 15
}
따라서, 자원의 일부를 수정할 때는 PATCH를, 전체적인 수정이 필요할 때는 PUT을 이용하는 것이 적절하다.
AWS EC2 CLI 환경에서 Public IP 주소 확인
1. curl 설치
$ sudo apt-get install curl
2. 다음 명령어 실행 후 잠시 기다리면 IP가 출된된다.
$ curl ifconfig.me
추상 클래스 vs 인터페이스
클래스에서 공통적으로 쓰이는 변수들을 따로 모아서 상속하려고 하는데 각 클래스마다 부분적으로 상속이 가능할까
AUTO_INCREMENT vs UUID vs EMAIL
Controller 코드 템플릿
package com.moham.coursemores.api;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("like")
@RequiredArgsConstructor
public class LikeController {
// 해당 컨트롤러의 이름과 일치해야한다
private static final Logger logger = LoggerFactory.getLogger(LikeController.class);
//반환할 결과값이 있다면 ResponseEntity<Map<String, Object>>
// 없다면 ResponseEntity<Void>
@GetMapping("test")
public ResponseEntity<Map<String, Object>> test() {
// 메서드 실행 - logger에 request값 표시하기 (없다면 none)
logger.info(">> request : none");
// 결과값을 담을 resultMap 생성
Map<String, Object> resultMap = new HashMap<>();
/* 해당 과정 반복
// service 실행
String test = testService.getTest();
// 결과값이 있다면 resultMap에 넣기
resultMap.put("test", test);
// logger에 결과값 표시하기 (없다면 none)
logger.info("<< response : test={}", test);
*/
// 결과값 반환하기
return new ResponseEntity<>(resultMap, HttpStatus.OK);
}
}
JPA, Hibernate, Spring Data JPA
JPA(Java Persistence Application)
Java 진영에서 ORM(Object-Relational Mapping) 기술 표준으로 사용하는 인터페이스 모음
자바 어플리케이션에서 관계형 데이터베이스를 사용하는 방식을 정의한 인터페이스
인터페이스 이기 때문에 Hibernate, EclipseLink등이 JPA를 구현함
Hibernate
자바 언어를 위한 ORM 프레임워크
JPA의 구현체로, JPA 인터페이스를 구현하며, 내부적으로 JDBC API를 사용
Spring Data JPA
public interface UserRepository extends JpaRepository<User, Integer> {
Optional<User> findByIdAndDeleteTimeIsNull(int userId);
}
개발하면서 가장 자주쓰는 방식이다. 원래는 EntityManager Class를 이용해서 함수를 하나하나 구현해야되는데 공통인터페이스를 제공해서 repository 개발 시 인터페이스만 작성하면 실행 시점에 스프링 데이터 JPA가 구현 객체를 동적으로 생성해서 주입하기 때문에 편리하게 사용가능
원래는 아래처럼 Law JPA를 사용해서 구현했는데 Spring Data JPA를 사용하면 편리하게 사용 가능!
@Repository
public class GuestbookRepository {
@PersistenceContext // EntityManagerFactory가 DI 할 수 있도록 어노테이션 설정
private EntityManager em;
public List<Guestbook> findAll(){
String jpql = "SELECT gb FROM Guestbook gb ORDER BY gb.regDate DESC";
TypedQuery<Guestbook> query = em.createQuery(jpql, Guestbook.class);
return query.getResultList();
}
}
git pull --rebase origin be-develop
git rebase --continue
git push -d origin be-feature/comment
Spring Boot에서 비동기적인 API 요청을 처리할 때는 기본적으로 각각의 요청이 별도의 스레드에서 동작하므로, 요청들이 병렬적으로 처리됩니다. 따라서, 프론트에서 비동기적으로 A와 B라는 API 요청을 보냈다면, Spring Boot는 A와 B 요청을 별도의 스레드에서 동시에 처리할 수 있습니다.
하지만, 각각의 요청이 서로에게 의존하는 경우에는 요청들이 순차적으로 처리되어야 합니다. 이 경우에는 Spring Boot에서 Callable과 DeferredResult 또는 @Async 어노테이션을 이용하여 순차적으로 처리할 수 있습니다. 예를 들어, A 요청의 처리 결과를 이용하여 B 요청을 처리해야 하는 경우, A 요청을 처리하는 Callable에서 B 요청을 호출하고, B 요청의 결과를 DeferredResult에 설정하여 반환하면 됩니다.
따라서, Spring Boot에서 API 요청의 순서는 각각의 요청이 독립적으로 처리되는지 여부에 따라 달라집니다. 요청들이 독립적으로 처리되어야 하는 경우에는 병렬적으로 처리될 수 있으며, 요청들이 서로에게 의존하는 경우에는 순차적으로 처리되어야 합니다.
'CS' 카테고리의 다른 글
불변성(Immutable)과 빌더 패턴(Builder Pattern)에 대해 (0) | 2024.01.03 |
---|---|
[CS] 데이터베이스 정규화와 이상현상(Normalization & Anomaly) (0) | 2023.04.19 |
[CS] 네트워크 (1) | 2023.02.28 |
[CS] Main Memory (0) | 2023.02.19 |
[CS] UI & UX에 대해 (0) | 2023.01.29 |