ORM(Object-Relational Mapping)
정의
ORM은 객체 관계 매칭이라고도 합니다.
필요 이유
데이터베이스와 객체지향 프로그래밍 간의 패러다임 불일치 문제를 해결하기 위해 고안된 프로그래밍 기술로, 객체 지향 프로그래밍 언어와 데이터베이스의 데이터를 서로 변환해주는 역할을 합니다.
데이터베이스와 객체지향 프로그래밍 간의 패러다임 불일치 때문에 개발자는 더 많은 코드를 작성해야 하며, 이는 반복적이고 실수하기 쉬운 작업이 됩니다. 그렇기 때문에 개발자는객체지향적인 설계에 집중할 수 없게 됩니다.
패러다임 불일치
객체 지향 프로그래밍과 관계형 데이터베이스 사이의 데이터 표현 방식이 달라서 생기는 문제를 패러다임 불일치라고 합니다. 패러다임 불일치가 일어나는 이유는 애초에 이들의 목표와 동작 방식이 다르기 때문입니다.
객체 지향
필드와 메서드 등을 묶어서 객체로 잘 만들어 사용하는 것이 목표
객체 지향 프로그래밍은 추상화, 캡슐화, 정보은닉, 상속, 다형성 등 시스템의 복잡성을 제어할 수 있는 다양한 장치들을 제공
관계형 데이터베이스
데이터를 잘 정규화해서 보관하는 것이 목표
제공 프레임워크
스프링 프레임워크에서는 JDBC 외에도 ORM을 지원하는 다양한 라이브러리와 프레임워크를 제공합니다.(ex, Hibernate, MyBatis, JPA(Java Persistence API) 등)
JPA(Java Persistence API)
정의
JPA는 Java Persistence API의 약자로, 자바 ORM 기술에 대한 API 표준 명세입니다. 즉, 인터페이스의 모음입니다.
구현 프레임워크
이러한 JPA 인터페이스를 구현한 대표적인 프레임워크가 하이버네이트(Hibernate)입니다.JPA는 애플리케이션과 JDBC 사이에서 동작합니다. 개발자가 JPA를 사용하면, JPA 내부에서 JDBC API를 사용하여 SQL을 호출하여 DB와 통신하게 됩니다. 즉, 개발자가 직접 JDBC API를 쓸 필요가 없습니다.
Hibernate
JPA를 구현한 프레임워크 중 사실상 표준입니다. 오픈소스 소프트웨어입니다. 여기서 주목해야할 점은 JPA는 기술 스펙이고 하이버네이트는 이 기능을 구현하여 공급해주는 역할이라는 것입니다.
Spring Data JPA
스프링에서 흔히 사용하는 것으로 알고있는 JPA는, JPA를 이용하는 spring-data-jpa 프레임워크이지 JPA는 아닙니다.Spring framework에서 JPA를 편리하게 사용할 수 있도록 지원하는 프로젝트(모듈)입니다. Spring Data JPA의 목적은 JPA를 사용할 때 필수적으로 생성해야하나, 예상가능하고 반복적인 코드들을 대신 작성해줘서 코드를 줄여주는 것입니다. 이는 JPA를 한 단계 추상화시킨 Repository라는 인터페이스를 제공함으로써 이루어집니다.
Spring Data JPA는 JPA Provider이 아닙니다. 단지 데이터 계층에 접근하기 위해 필요한 뻔한 코드들의 사용을 줄여주도록 하는 인터페이스입니다. 여기서 반드시 기억해야할 점은 Spring Data JPA는 항상 하이버네이트와 같은 JPA provider가 필요하다는 것입니다.
빌더 패턴(Builder Pattern)
정의
빌더 패턴(Builder pattern) 이란 복합 객체의 생성 과정과 표현 방법을 분리하여 동일한 생성 절차에서 서로 다른 표현 결과를 만들 수 있게 하는 패턴입니다.
사용 이유
생성자 인자로 너무 많은 인자가 넘 져지는 경우 어떠한 인자가 어떠한 값을 나타내는지 확인하기 힘듭니다.
또 어떠한 인스턴스의 경우에는 특정 인자만으로 생성해야 하는 경우가 발생합니다. 특정 인자에 해당하는 값을 null로 전달해줘야 하는데, 이는 코드의 가독성 측면에서 매우 좋지 않다는 것을 알 수 있습니다.
Lombok을 이용한 생성 방법
빌더 패턴으로 생성자 Class 생성 후 빌더 Class 생성의 방식도 가능하지만 클래스를 만들 때마다 코드를 만들어야 하기 때문에 코드가 굉장히 길어지고, 불편해질 수 있습니다. 이때 Lombok을 이용하여 이런 단점을 매꿀 수 있다.
빌더 패턴을 적용할 클래스
public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;
@Builder
public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium, int carbohydrate) {
this.servingSize = servingSize;
this.servings = servings;
// ...
}
}
다음과 같이 클래스 또는 생성자에 @Builder 애노테이션을 붙여주면 builderMethodName에 들어간 이름으로 빌더 메소드를 생성해줍니다.
클래스에 붙여주는 것보다, 생성자에 붙여주는 게 좋습니다. @Builder를 클래스에 달아주면 @AllArgsConstructor도 같이 달아주는 것과 같기 때문에 바람직하지 않기 때문입니다.
Bulider 패턴을 사용하여 생성자 생성
NutritionFacts.NutritionFactsBuilder builder = NutritionFacts.builder();
builder.calories(230);
builder.fat(10);
NutritionFacts facts = builder.build();
NutritionFacts facts = NutritionFacts.builder()
.calories(230)
.fat(10)
.build();
장점
1) 필요한 데이터만 설정할 수 있음
객체 생성 시 필요 없는 필드가 있는 경우, 더미 값을 넣어주거나, 생성자를 새로 만들어야 하지만, 빌더 패턴을 사용하면 동적으로 처리가 가능합니다.
2) 유연성을 확보할 수 있음
원하는 필드 조합으로 되어진 생성자가 없다면 해당 객체를 해당 필드 조합으로 만들 수 없거나 새로운 코드를 추가해야 합니다. 하지만, 빌더 패턴을 사용하면 새로운 변수가 추가되는 상황에도 기존 코드에 영향을 주지 않습니다.
3) 가독성을 높일 수 있음
매개변수가 많아져도 가독성을 높여 각각의 값들이 무엇을 의미하는지 파악이 편합니다.
4) 불변성을 확보할 수 있음
setter를 구현하지 않아도 괜찮기 때문에 확장 가능성을 불필요하게 열어두지 않아도 됩니다.
트랜잭션( Transaction )
정의
트랜잭션은 더 이상 쪼갤 수 없는 최소 작업 단위를 의미합니다. 그래서 트랜잭션은 commit으로 성공 하거나 rollback으로 실패 이후 취소되어야 합니다.
사용 이유
만약 데이터베이스의 데이터를 수정하는 도중에 예외가 발생된다면 어떻게 해야 할까요? DB의 데이터들은 수정이 되기 전의 상태로 다시 되돌아가져야 하고, 다시 수정 작업이 진행되어야 할 것입니다.
이렇듯 여러 작업을 진행하다가 문제가 생겼을 경우 이전 상태로 롤백하기 위해 사용되는 것이 트랜잭션(Transaction) 입니다.
대표적인 예시로, 계좌 이체를 생각해볼 수 있습니다.
트랜잭션 성격(ACID 원칙)
원자성(Atomicity)
|
하나의 트랜잭션은 모두 하나의 단위로 처리되어야 합니다.
예를 들어 트랜잭션이 A, B의 작업으로 구성되면 항상 A, B의 처리 결과는 동일해야 합니다.
즉, A는 성공했으나 B는 실패했을 경우 A,B는 원래 상태로 되돌려져야합니다.(rollback)
어떤 작업이 잘못되는 경우 모든 것은 다시 원점으로 되돌아가야 합니다.
|
일관성(Consistency)
|
트랜잭션이 성공했다면 데이터베이스의 모든 데이터는 일관성을 유지해야 합니다.
트랜잭션으로 처리된 데이터와 일반 데이터 사이에는 차이가 없어야 합니다.
|
격리(Isolation)
|
트랜잭션으로 처리되는 중간에 외부에서의 간섭은 없어야 합니다.
|
영속성(Durability)
|
트랜잭션이 성공적으로 처리되면, 그 결과는 영속적으로 보관되어야 합니다.
|
@Transactional
정의
@Transactional을 이용하여 메서드, 클래스, 인터페이스의 트랜잭션 처리가 가능한데 이러한 방식을 선언적 트랜잭션이라 부릅니다.
사용 용도
스프링은 간단한 트랜잭션 매니저의 설정과 @Transactional 어노테이션을 이용한 설정으로 애플리케이션 내의 트랜잭션에 대한 설정을 처리할 수 있습니다.
예제
@Transactional 어노테이션은 메서드뿐만 아니라 클래스, 인터페이스에 설정이 가능합니다.
@Service
public class MemberService {
```
@Transactional
public void addMember(MemberDto memberDto) throws Exception {
// 멤버 삽입 로직 구현
}
```
}
어노테이션의 우선순위
메서드의 @Transactional 설정 > 클래스의 @Transactional 설정 > 인터페이스의 @Transactional 설정
스프링 프레임워크 기초: ORM(Object-Relational Mapping) 개념과 활용하기 (tistory.com)
ORM(Object Relational Mapping)이 뭘까? 🤔 (tistory.com)
[Spring JPA] JPA 란? (tistory.com)
[Spring] Spring Data JPA 이해하기 (feat ORM, JPA) (tistory.com)
빌더 패턴(Builder Pattern) - 기계인간 John Grib
[Spring] Builder 패턴 생성 및 장점 사용이유 설명 (코드 생성) :: Jung's (tistory.com)
[Spring] 트랜잭션에 대한 이해와 Spring이 제공하는 Transaction(트랜잭션) 핵심 기술 - (1/3) - MangKyu's Diary (tistory.com)
[Spring/스프링] - 트랜잭션 @Transactional 이란? : 네이버 블로그 (naver.com)
'SERVER' 카테고리의 다른 글
[3기 SERVER 스터디] 2주차(A) - Spring Boot3 입문 (0) | 2024.10.08 |
---|---|
[SERVER 스터디] 5주차 스터디 - ERD (Entity Relationship Diagram) 란? (1) | 2023.10.15 |
[SERVER 스터디] 2주차(B) - 간단한 Controller와 테스트 코드 작성 (0) | 2023.09.30 |
[SERVER 스터디] 2주차(A) - Spring Framework 기본 개념 (0) | 2023.09.30 |
[SERVER 스터디] 1주차 스터디 - 깃 & 깃허브 (GIT & Git-Hub) (0) | 2023.09.20 |