프로젝트 구조 다음과 같이 상품 목록을 조회하는 프로젝트 구조를 알아보자. build.gradle plugins { id 'org.springframework.boot' version '2.6.5' id 'io.spring.dependency-management' version '1.0.11.RELEASE' id 'java' } group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '11' configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.spr..
체크 예외와 인터페이스 서비스 계층에서 처리할 수 없는 예외의 의존을 제거해서 서비스 계층을 순수하게 유지할 수 있다. 먼저, 인터페이스를 도입해서 구현체를 쉽게 변경할 수 있도록 만들어보자. 인터페이스 도입 그림 이렇게 인터페이스를 도입하면 서비스는 인터페이스에만 의존하면 된다. 이 때 체크 예외를 사용하는 경우 인터페이스에서도 예외처리를 해결해야한다. 체크 예외 코드에 인터페이스 도입 시 문제점 public interface MemberRepositoryEx { Member save(Member member) throws SQLException; Member findById(String memberId) throws SQLException; void update(String memberId, int ..
자바 예외 이해 예외 계층 스프링이 제공하는 예외 추상화를 이해하기 위해선 자바 기본 예외에 대한 이해가 필요하다. 실무에 필요한 체크 예외와 언체크 예외에 대해 알아보자. Throwable 은 최상위 예외로 하위에 Exception 과 Error 가 있다. Error 는 메모리 부족이나 심각한 시스템 오류와 같이 애플리케이션에서 복구 불가능한 시스템 예외이다. 애플리케이션 개발자는 이 예외를 잡으려고 해서는 안된다. 상위 예외를 catch로 잡으면 그 하위 예외까지 잡기 때문에 애플리케이션 로직은 최상위인 Exception 까지만 잡는 것이 올바르다. 참고로 Error 도 언체크 예외이다. Exception : 체크 예외 애플리케이션 로직에서 사용할 수 있는 실질적인 최상위 예외이다. Exception..
스프링과 문제 해결 순수한 서비스 계층 서비스 계층은 특정 기술에 종속적이지 않게 개발해야 한다. 계층을 나눈 이유도 서비스 계층을 최대한 순수하게 유지하기 위한 목적이 크다. 즉, 한 마디로 JDBC를 쓰다 JPA로 변경, Http API를 쓰다가 GRPC로 변경 등에 대한 과정으로 인해 서비스 계층에 수정이 있으면 안된다. 스프링은 트랜잭션 문제 (JDBC에 의존하는 문제, 트랜잭션 동기화, 반복 문제), 예외 누수 등의 문제를 해결할 수 있는 다양한 방법을 제공한다. 트랜잭션 추상화 트랜잭션은 원자적 단위의 비즈니스 로직을 처리하기 위해 사용한다. JDBC, JPA 등 구현 기술마다 트랜잭션을 사용하는 방법이 다르다. (JDBC : setAutoCommit(false), JPA : transacti..
트랜잭션 개념 이해 트랜잭션은 이름 그대로 번역하면 거래라는 뜻이다. 즉, 데이터베이스에서 트랜잭션은 하나의 거래를 안전하게 처리하도록 보장해주는 것을 의미한다. 데이터를 저장할 때 파일 저장이 아닌, 데이터베이스에 저장하는 이유 중 대표적인 이유는 트랜잭션을 지원하기 때문이다. 하나의 트랜잭션이 모두 성공해서 데이터베이스에 반영되는 것을 커밋이라하고, 작업 중 하나라도 실패해서 거래 이전으로 되돌리는 것을 롤백이라 한다. 트랜잭션 ACID 트랜잭션은 원자성(Atomicity), 일관성 (Consistency), 격리성(Isolation), 지속성(Durability)를 보장해야 한다. 원자성 : 트랙잭션 내에서 실행한 작업들은 마치 하나의 작업인 것처럼 모두 성공하거나 실패해야 한다. 일관성 : 모든 ..
커넥션 풀 이해 데이터베이스 커넥션 획득 과정 애플리케이션 로직은 DB 드라이버를 통해 커넥션을 조회한다. DB 드라이버는 DB와 TCP/IP 커넥션을 연결한다. (3 way handshake 등) DB 드라이버는 TCP/IP 커넥션이 연결되면 ID, PW등 필요한 부가 정보를 DB에 전달한다. DB는 ID,PW를 통해 내부 인증을 완료하고, 내부에 DB 세션을 생성한다. DB는 커넥션 생성이 완료되었다는 응답을 받는다. DB 드라이버는 커넥션 객체를 생성해서 클라이언트에 반환한다. 이렇게 커넥션을 새로 만드는 것은 과정도 복잡하고 시간이 많이 소모되는 작업이다. 이런 문제를 해결하는 아이디어가 바로 커넥션을 미리 생성해두고 사용하는 커넥션 풀 방법이다. 애플리케이션 시작 시점에 커넥션 풀은 필요한 만큼..
프로젝트 생성 Build.gradle dependencies { implementation 'org.springframework.boot:spring-boot-starter-jdbc' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' //테스트에서 lombok 사용 testCompileOnly 'org.projectlombok:lombok' testAnnotationProcessor 'org.projectlombok:lo..
파일 업로드 HTML 폼 전송 방식에는 application/x-www-form-urlencoded, multipart/form-data 두 가지가 있다. 파일 업로드를 이해하려면 이 두 가지 방식의 차이에 대해 이해해야 한다. HTML 폼데이터를 서버로 전송하는 가장 기본적인 방법으로, 별도의 enctype이 없으면 웹 브라우저는 요청 HTTP 메시지의 헤더에 Content-Type: application/x-www-form-urlencoded 를 추가한다. 여기서 단점은 보내야할 데이터가 여러 개인 경우, 문자와 바이너리를 동시에 전송해야하는 상황이 자주 있다는 것이다. 이 문제를 해결하기 위해 HTTP는 multipart/form-data 라는 전송 방식을 제공한다. multipart/form-da..