▶ 단축키
https://mangkyu.tistory.com/139
https://smpark1020.tistory.com/423
surround with (try/catch) : option + command + t
자동 정렬 : option + command + L
getter/setter : control + Enter
찾기(검색) : command + shift + f
class, enum 등 없는거 생성 : option + Enter
Generate(constructor, getter/setter..) : command + n
▶ 프레임워크
뼈대나 근간을 이루는 코드들의 묶음.
라이브러리란, 개발자가 작성해놓은 코드파일을 의미하며
API란, 여러 라이브러리가 모여있는 패키지(JAR)을 의미한다.
프레임워크란, API가 굉장히 많이 모여져서 덩치가 커져잇는 것을 의미한다.
개발자는 각 개개인의 능력차이가 큰 직종이고, 개발자 구성에 따라 프로젝트 결과 역시 큰 차이를 낳는다. 이런 상황을 극복하기 위한 코드의 결과물이 바로 프레임워크이다. 프로그램의 기본 흐름이나 구조를 정하고 모든 팀원이 이 구조에 자신의 코드를 추가하는 방식으로 개발하게 된다.
- 프레임워크의 장점
개발에 필요한 구조를 이미 코드로 만들어 놓았기 때문에, 실력이 부족한 개발자라 하더라도 반쯤 완성한 상태에서 필요한 부분을 조립하는 형태의 개발이 가능하다. 회사 입장에서는 프레임워크를 사용하면 일정한 품질이 보장되는 결과물을 얻을 수 있고, 개발자 입장에서는 완성된 구조에 자신이 맡은 서비스에 대한 코드를 개발해서 넣기 때문에 개발 시간을 단축할 수 있다.
▶ 스프링 프레임워크
경량 프레임워크(light-weight)
예전 프레임워크는 다양한 경우를 처리할 수 있는 다양한 기능을 가지도록 만들다보니, 하나의 기능을 위해서 너무 많은 구조가 필요했다. 기술이 너무나 복잡하고 방대했기 때문에, 전체를 이해하고 개발하기에는 어려움이 많았다.
그래서 스프링 프레임워크가 등장했고, 특정 기능을 위주로 간단한 JAR파일 등을 이용해서 모든 개발이 가능하도록 구성되어 있다.
- 스프링 프레임워크의 장점
1) 복잡함에 반기를 들어서 만들어진 프레임워크(경량화)
2) 프로젝트 전체 구조를 설계할 때 유용한 프레임워크(서버 제작의 빠른 속도)
3) 다른 프레임워크들의 포용,
여러 프레임워크를 혼용해서 사용 가능하며 이를 접착성이라고 한다.
4) 개발 생산성과 개발도구의 지원
- 스프링 프레임워크의 특징
1) POJO 기반의 구성
2) DI를 통한 객체간의 관계 구성
3) AOP 지원
4) 트랜잭션 관리
5) 편리한 MVC 구조
6) WAS에 종속적이지 않은 개발 환경
[POJO(Plain Old Java Object) 기반의 구성]
오래된 방식의 간단한 자바 객체라는 의미이며, JAVA 코드에서 일반적으로
객체를 구성하는 방식을 스프링 프레임워크에서 그대로 사용할 수 있다는 말이다.
[DI(Dependency Injection)를 통한 객체간의 관계 구성]
의존성(Dependency)이란 하나의 객체가 다른 객체 없이 제대로 된 역할을 할 수 없다는 것을 의미한다. 예를 들어 A객체가 B객체 없이 동작이 불가능한 상황을 'A가 B에 의존적이다'라고 표현한다.
주입(Injection)은 말 그대로 외부에서 밀어 넣는 것을 의미한다.
예를 들어 어떤 객체가 필요로하는 객체를 외부에서 밀어 넣는 것을 의미한다.
주입을 받는 입장에서는 어떤 객체인지 신경 쓸 필요가 없고 어떤 객체에 의존하던 자신의 역할은 변하지 않는다.
**의존성
ⓐ →→→→→→→→→→→→→→→→→→→→→ ⓑ
ⓐ객체에서 ⓑ객체를 직접 생성
**의존성 주입
ⓐ →→→→→→→→→???↔↔↔↔↔↔↔↔↔ ⓑ
ⓐ는 ⓑ가 필요하다는 신호를 보내고, ???가 ⓑ객체를 외부에서 생성하여 주입하게 된다.
의존성 주입방식을 사용하기 위해서는 ???라는 존재가 필요하게 된다.
스프링 프레임워크에서는 ApplicationContext가 ???라는 존재이며,
필요한 객체들을 생성하고, 필요한 객체들을 주입해주는 역할을 한다.
따라서 개발자들은 기존의 프로그래밍과 달리 객체와 객체를 분리해서 생성하고,
이러한 객체들을 엮는(wiring) 작업의 형태로 개발하게 된다.
ApplicationContext가 관리하는 객체들을 빈(Bean)이라 부르고, 빈과 빈 사이의 의존 관계를 처리하는 방식으로는 XML, 어노테이션, JAVA 방식이 있다.
Context (메모리 상에 존재하는 영역)
IOC 컨테이너 * IOC : 제어의 역전 |
[AOP(Aspect Oriented Programming) 지원]
관점 지향 프로그래밍.
좋은 개발환경에서는 개발자가 비지니스 로직에만 집중할 수 있게 한다.
스프링 프레임워크는 반복적인 코드를 제거해줌으로써 핵심 비지니스 로직에만 집중할 수 있는 방법을 제공한다. 보안이나 로그, 트랜잭션, 예외처리와 같이 비지니스 로직은 아니지만, 반드시 처리가 필요한 부분을 횡단 관심사(cross-concern)라고 한다.
스프링 프레임워크는 이러한 횡단 관심사를 분리해서 제작하는 것이 가능하고 횡단 관심사를 모듈로 분리하는 프로그래밍을 AOP라고 한다. 핵심 비지니스 로직에만 집중하여 코드 개발이 가능해지고, 각 프로젝트마다 다른 관심사 적용 시 코드 수정을 최소화할 수 있으며, 원하는 관심사의 유지보수가 수월한 코드로 구성이 가능해진다.
[트랜잭션 관리]
DB 작업 시 트랜잭션을 매번 상황에 맞게 코드로 작성하지 않고, 어노테이션이나 XML로
트랜잭션을 쉽게 관리할 수 있다.
(트랜잭션 : DML, 서비스의 최소단위)
[단위 테스트]
전체 Application을 실행하지 않아도 기능별 단위 테스트가 용이하기 때문에 버그를 줄이고 개발 시간을 단축할 수 있다. (Junit API)
▶ 스프링 부트
스프링 프레임워크를 사용함에 있어서 초기 설정 및 필요한 라이브러리에 대한 설정의 어려움이 많으며, 시간이 너무 많이 걸리기 때문에 자동 설정(AutoConfiguration)과 개발에 필요한 모든 것을 관리해주는 스프링 부트를 선호한다. 각 코어 및 라이브러리의 버전들도 맞추어야 하지만 스프링 부트를 사용하면 이러한 복잡성을 해결하기에도 좋다.
▶ 프로젝트 기본 경로
1) src/main/java : 서버단 JAVA 파일
2) test/main/java : 단위 테스트 JAVA 파일 (Junit, Assertions)
3) src/main/resource : 설정 파일 및 뷰단
4) resources/static : css, js, image 파일 경로
5) resources/templates : html 파일 경로
6) pom.xml : 라이브러리 의존성 관리
7) application.properties : 서버 및 DB, 라이브러리 설정 파일
(application.yml)
8) build.gradle :
▶ 프로젝트 생성
[2021.ver]
create new project
> spring initializr
(초기환경을 알아서 만들어줌 /Spring은 웹 사이트 내에서 만들어 커스터마이징)
java 버전 잘 체크!
> Group : 시작 패키지
Artifact : 프로젝트명
type : Project를 주로 사용함,
Config, POM (세부설정이 많은 경우),
Gradle : 파일 내에서 연산o, 객체 형식 / Maven : 파일 내에서 연산x, xml 형식
⇒ 공통점 : 코드를 작성하면 API를 자동으로 다운해준다.
Packaging : Jar / War (콘솔 출력 x)
Java version : 사용 자바 버전
Version : 프로젝트 버전
> 필요한 프레임워크 추가 (spring boot version 체크)
> location 체크 후 Finish
[2023.ver]
create new project
> spring initializr
(초기환경을 알아서 만들어줌 /Spring은 웹 사이트 내에서 만들어 커스터마이징)
java 버전 잘 체크!
> Group : 시작 패키지
Artifact : 프로젝트명
type : Gradle Groovy
Packaging : Jar / War (콘솔 출력 x)
Java version : 사용 자바 버전
Version : 프로젝트 버전
> 필요한 프레임워크 추가 (spring boot version 체크 2.7.x 버전)
> location 체크 후 Finish
[만약 오류가 날 경우]
ex) 프로젝트 생성 후 첫 화면에서 [spring initializr / Error : Request failed with status code 500] 라고 뜬 경우
https://start.spring.io/ 로 들어가서 위의 프로젝트 설정과 같이 한다.
> 프레임워크 추가하는 방법
ADD DEPENDENCIES… 클릭 후 추가
> GENERATE 후 압축파일을 원하는 위치에 풀면 완료.
▶ Plugin 설치
Preference > Plugin > keyword search
▶ 어노테이션
@Data
생성자, getter, setter, toString, equals, hashcode 를 만들어주는 어노테이션
@Getter @Setter
getter, setter를 만들어주는 어노테이션
@NoArgsConstructor
기본 생성자를 만들어주는 어노테이션
@Component
spring이 관리할 수 있는 대상으로 만드는 어노테이션 (컨테이너에 등록)
@Bean * Bean과 Component의 차이점
IOC 컨테이너에 Bean을 등록하는 어노테이션
@Autowired
Injection 하는 어노테이션
- 필드 주입
@Component @Data public Example{ @Autowired private final Test test; } |
- 사용 방법이 매우 편하다.
- 주입된 객체를 불변(immutable)상태로 만들 수 없기 때문에 외부에서 수정될 위험이 있다.
(한 번 요청했던 주소값을 바꾸게 되면 심각한 오류가 발생할 수 있다. → cache에 저장해놓았는데 주소가 바뀌게 되면 불러오지 못하는 오류가 생기게 된다.)
- 생성 후 주입, 생성 시점에는 순환 참조 발생 여부를 알 수 없다.
- 순환 참조(무한반복)가 발생했을 때 예외가 발생하지 않는다. → 스택오버플로우 발생
- 해당 클래스가 메모리에 올라갈 때 필드를 기준으로 가기 때문에
메소드 안의 객체는 고려하지 않는다. 로컬 영역에서는 직접 객체화를 해주어야한다.
- 주입이 되지 않아도 객체는 생성되기 때문에 NPE 방어 불가
- 단위 테스트에서는 필드 주입을 사용한다. 그 외의 곳에서는 생성자 주입.
- Setter 주입
@Component @Data @NoArgsConstructor public Example{ private Computer computer; @Autowired public void setComputer(Computer computer) { this.computer = computer; } } |
- 주입 받는 객체가 변경될 가능성이 있는 경우에 사용한다.
- OCP (Open-Closed Principle, 개방-폐쇄 원칙)를 위반하기 때문에 변경 가능성을 배제하고 불변성을 보장하는 것이 좋다.
- 생성 후 주입, 생성 시점에는 순환 참조 발생 여부를 알 수 없다.
- 생성자 주입
@Component @Data public Example{ private final Test test; @Autowired // 생략가능 public Example(Test test){ this.test = test; } } |
- final을 붙일 수 있다.
(생성자를 생성할 때 초기화하기 때문에 final을 붙여도 오류가 나지 않는다.)
@RequiredArgsConstructor (생성자 주입)
final이 붙은 필드만 초기화 해주는 어노테이션
@Component @Data @RequiredArgsConstructor public Example{ private final Test test; int data; } |
- 메모리에 필드를 할당하면서 초기값이 주입되므로 final 키워드를 사용할 수 있음
- 주입이 되지 않으면 객체 자체가 생성되지 않으므로 NPE 방어 가능
@AllArgsConstructor
모든 필드를 초기화 하는 생성자를 만들어주는 어노테이션
@SpringBootTest
Junit 라이브러리를 이용하기 위한 어노테이션
@Slf4j
출력 어노테이션 (main 메소드 외 System.out.print() 사용 x)
@Test
Junit에게 테스트 할 수 있다고 알려주는 어노테이션
@Qualifier(“”)
어떤 타입인지 구분하는 어노테이션
@Primary
Default 타입을 지정해주는 어노테이션
@Configuaration
설정을 위한 어노테이션
@ConfiguarationProperties
properties에 있는 설정들을 주입하는 어노테이션
- prefix = “” : “”로 시작하는 설정들
@Mapper
mapper 어노테이션
ApplicationContext 동작 → mapper가 사용되면 구현체 생성 후 @mapper를 스캔
@Select(“sql 문”)
간단한 sql문을 직접 넣고, 복잡한 sql문은 interface와 연결하여 메소드 이름과 id를 동일하게 작성하여 사용한다.
@Controller
controller 어노테이션
@ReqeustMapping(“/ex/*”)
Handler Mapping에게 경로를 알려주는 어노테이션
@ModelAttribute(“”)
component에 없는 값을 전달하거나 받고 싶을 때,
controller에서 매개변수 앞에 붙여주는 어노테이션
(변수가 많아지면 가독성이 안좋아진다. 그럴 때는 Model 객체를 매개변수로)
public void ex(Model model){
model.addAttribute(“name”, name);
}
@RequestBody
Controller 에서 REST
▶ JNDI * 참고자료, JDBC, DBCP, JNDI 차이점
외부파일에 있는 데이터 소스 객체를 자바로 옮겨오는 것
▶ DB 연결
1. application.properties 설정
2. java/main/package/mybatis/MyBatisConfig.java
- ApplicationContext를 받아와 ApplicationContext가 실행되면 Mybatis가 실행되도록 한다.
- Mybatis Library 이름 : hikari
- 메소드 안에서 메소드를 이용하기 위해서 return new ~ 를 사용한다.
- DataSource로 Connection 객체를 가져온다.
- SqlsessionFactoryBean : SqlsessionFactory 설정들을 넣을 수 있다.
(이미 있는 Builder가 이 설정으로 빌드해준다.)
- sqlsessionFactoryBean.set~ : 설정들을 해준다.
- applicationContext가 resources의 경로를 알고 있다.
- classpath : resources까지의 경로
- sqlsessionFactoryBean.getObject() : 설정들로 빌드된다.
- sqlsessionFactory.getConfiguration().getMapUnderscoreToCamelCase() : 카멜표기법
- return이 객체타입 → 객체이므로 @Bean으로 spring에게 알려줘야한다.
3. resources/config/config.xml
3. resources/mapper/~Mapper.xml
- mapper를 Interface와 연결
→ 자바에서는 Interface의 추상메소드를 사용
→ 연결된 쿼리가 실행
→ 구현체가 생성되면 해당 메소드에 들어감.
- namespace=”interface의 경로” : interface와 연결
▶ try statement
외부 장치를 열 때, 소괄호에 connetion 객체를 가지고 오면 자동으로 close 된다.
try(Connection connection = dataSorce.getConnection()){ ~ } catch(Exception e){ e.printStackTrace(); } |
▶ xml 파일도 포함하여 빌드 및 배포하는 resource
pom.xml
→ <build> 아래
<resources> <resource> <directory>src/main/resources</directory> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.xml</include> <include>**/*.properties</include> <include>**/*.setting</include> </includes> </resource> </resources> |
→ 옆의 새로고침 클릭
▶ Mybatis 쿼리 실행의 결과 테이블을 보는 방법
log4jdbc-log4j2로 driver를 연결, 내부적인 동작을 가져올 수 있는 권한을 가짐. (spy를 통해)
pom.xml
→ dependencies 하단
<dependency> <groupId>org.bgee.log4jdbc-log4j2</groupId> <artifactId>log4jdbc-log4j2-jdbc4</artifactId> <version>1.16</version> </dependency> |
→ 옆의 새로고침 클릭
* 만약 spy가 읽어올 수 없는 데이터 (unread)로 뜰 경우, 실제 DB에서 확인
▶ Spring MVC (Front-Controller-Pattern)
2) DispatcherServlet은 요청받은걸. HandlerMapping한테 보내준다.
3) HandlerMapping은 해당 요청을 해결할 controller를 선택해서 DispatcherServlet에게 보내준다.
4) DispatcherServlet이 HandlerAdapter에게 해당 Controller를 알려준다.
5) HandlerAdapter는 해당 controller의 메소드중 요청을 처리하기에 알맞은 메소드를 정해서 데이터를 처리하게하고(service와 dao등을 이용하여 데이터 처리) 결과가 담긴. model과 view를 DispatcherServlet에게 넘겨준다.
6) DispatcherServlet은 ViewResolver에게 view를 표현하기 적합한 jsp페이지를 선택해달라고 요청한다.
8) ViewResolver는 적합한 jsp페이지를 알려준다.
9) DispatcherServlet은 해당 jsp 페이지에 응답을 생성하고 생성된 응답은 클라이언트에게 보내진다. (jsp형태)
특징
- HttpServletRequest, HttpServletResponse를 거의 사용할 필요 없이 기능 구현
- 다양한 타입의 파라미터 처리, 다양한 타입의 리턴 타입 사용이 가능
- GET방식, POST방식 등 전송 방식에 대한 처리를 어노테이션으로 처리 가능
▶ Controller
@Controller @RequestMapping(“/ex/*”) @Slf4j public class ExampleController{ @RequestMapping(“/ex01”) // 아래의 설정이 생략된 상태 @RequestMapping(value = “/ex01”, method = {RequestMethod.GET, RequestMethod.POST}) public String ex01(){ log.info(“ex01………..”); return “text”; } } |
- 경로를 설정하지 않고 하고 싶다면 void로 (ex/ex01)
- 경로를 따로 지정할 경우에는 String으로 한다 (return “test” ⇒ test)
@Controller @RequestMapping(“/ex/*”) @Slf4j public class ExampleController{ @GetMapping(“/ex02”) public void ex02(String name){ log.info(name); } } |
- @GetMapping, @PostMapping .. 으로 설정가능하다.
- request.getParameter(“name”) 으로 쓰지 않고 name으로 써도 된다. (자동으로 해준다.)
@GetMapping(“/ex04”) public void ex04(@RequestParam(“id”) String name, int age){ } |
▶ Thymeleaf
html에서 연산이 가능하도록 해주는 라이브러리
- th: 으로 시작하고 ${}를 이용한다. 태그의 속성값으로 사용한다.
- controller에서 받은 매개변수가 자동으로 넘어와서 사용할 수 있다.
(첫글자 소문자로 바꿔서 사용 가능)
- 반복되는 코드를 줄일 수 있다. 부모의 태그에 반복되는 것을 묶어 둘 수 있다.
이때에는 $가 아니라 *(참조)로 사용해야한다.
<!DOCTYPE html> <head> <meta charset="UTF-8"> <title>EX03</title> </head> <body> <table border="1"> <tr> <th>이름</th> <th>나이</th> </tr> <tr> <td th:text="*{memberVO.name}"></td> <td th:text="*{memberVO.age}"></td> </tr> <tr th:object="${memberVO}"> <td th:text="*{name}"></td> <td th:text="*{age}"></td> </tr> </table> </body> </html> |
▶ 3-tier
스프링 프로젝트는 3-tier(티어)방식으로 구성한다.
[Presentation Tier(화면 계층)]
화면에 보여주는 기술을 사용하는 영역
컨트롤러에서 사용자의 요청에 맞는 응답처리를 진행하며,
HTML 엔진(Thymeleaf), HTML 등이 담당하는 영역이다.
[Business Tier(비즈니스 계층)]
순수한 비즈니스 로직을 담고 있는 영역
고객이 원하는 요구사항을 반영하는 계층이기 때문에 중요한 영역이다.
이 영역의 설계는 고객의 요구사항과 정확히 일치해야 하며, 서비스 영역이라고 부른다.
[Persistence Tier(영속 계층)]
데이터를 어떤 방식으로 보관하고 사용하는 가에 대한 설계가 들어가는 계층
일반적으로 DBMS를 많이 이용한다.
Presentation ↔ Business ↔ Persistence tier ↔ DBMS ↑ ↑ Service Interface Mapper Interface |
▶ Rest (Representational State Transfer)
▶ AOP(Aspect Oriented Programming)
관점이란 개발에 있어서, 관심사(Concern)를 의미한다.
코드의 중복을 줄일 수 있으며, 핵심 로직과 주변 로직을 분리하여 관리할 수 있다.
- 파라미터가 잘 전달 되었는가?
- 이 로직에서 발생할 수 있는 예외가 모두 처리되었는가?
핵심 로직은 아니지만 반복적으로 개발에 필요한 관심사들을 주변 로직이라고 한다.
따라서 AOP는 이러한 주변 로직을 횡단 관심사로 분리하여 작성하고
종단 관심사인 핵심 비지니스 로직만을 작성하도록 한다.
사용할 수 있는 시점
- Around(전역)
- Before(메소드 시작 직후)
- After(메소드 종료 직전)
- AfterReturning(메소드 리턴 후)
- AfterThrowing(메소드 예외 발생 후)
▶ Proxy 프록시 : 가짜 객체
▶ ORM(Object Relational Mapping)
객체 진영과 RDB 진영을 자동으로 매핑하여 구조의 불일치를 개발자 대신 해결해주는 기술의 총칭이다. 객체지향 구조에서 프로그래밍 언어를 사용하여 RDB의 데이터를 조작하는 방법이다. ORM을 사용하면 개발자가 SQL문을 직접 작성하지 않아도 RDB와 상호작용할 수 있다.
▶ JPA (Java Persistence API)
ORM을 사용하기 위한 설계도(틀)이다.
Java Application용 RDB 매핑 관리를 위한 인터페이스이며, DBMS 벤더사에 의존하지 않고 독립적으로 ORM을 사용할 수 있는 ORM 표준이다. 인터페이스이기 때문에 구현되어 있지 않은 틀만 제공하며, 자체적인 작업을 수행하지 않는다. JPA에 설계된 구조에 맞춰서 각 메소드를 재정의하여 직접 ORM을 구현하여 사용해야 한다.
JPA는 ORM을 사용할 수 있는 JAVA 인터페이스를 제공하는 ORM 접근 방식이며, 구현되지 않은 JPA를 ORM이라고 말하기는 어렵다.
▶ Hibernate Framework
모든 Java Application에 대해 객체 관계를 그대로 유지한 채 쿼리 서비스를 제공하는 오픈 소스(비용 없이 공개적으로 사용 가능)의 경량 ORM이다. JPA를 구현한 구현체이며, 여러 구현체 중 가장 대표적인 구현체이다. 객체 간 관계 구성을 지원하며, 상속, 지연성, 페이징 처리, 예외 처리 불필요를 지원한다.
▶ Spring Data JPA
JPA를 추상화한 Repository 인터페이스를 제공하여 JPA를 쓰기 편하게 다양한 기능을 지원한다. 내부적으로는 JPA를 사용한다. JPA를 모르면 내부 구조를 이해 하기 힘들 수 있다.
▶객체와 관계형 데이터베이스의 차이
1. 상속
[개발자] [기획자]
번호 번호
-------- --------
이름 이름
생년월일 생년월일
경력 경력
기술등급 OA등급
프로젝트수 클라이언트수
▷ 슈퍼-서브타입 도출
[사원] - 슈퍼
번호(PK)
---------
이름
생년월일
경력
[개발자] - 서브 [기획자] - 서브
번호(PK,FK) 번호(PK,FK)
------------ ------------
기술등급 OA등급
프로젝트수 클라이언트수
1:1관계에서 INSERT를 하기 위해서는 쿼리를 2번 작성해야하는 불편함이 생긴다. 게다가 조회를 할 때에는 JOIN을 사용 해야 하는데 쿼리가 굉장히 복잡해진다.
만약 이러한 RDB의 테이블 관계를 만약 자바 컬렉션으로 바꿀 수 있다면,
Developer developer = list.get(developerId);
위와 같이 간단하게 조회할 수 있다.
2. 연관관계
객체는 하위 연산자(.)를 사용하여 참조를 한다.
▶ 객체 연관 관계 : 단방향으로 흘러간다(Flower에서 Pot 접근은 가능하지만 Pot에서 Flower를 접근할 수 없다)
※ → 는 의존성의 방향을 의미한다.
Flower → Pot
id id
flowerName shape
Pot pot color
▶ RDB 연관 관계 : 양방향으로 흘러간다(FLOWER에서 POT을 POT에서 FLOWER를 접근할 수 있다)
FLOWER → POT
FLOWER_ID(PK) POT_ID(PK)
------------- -------------
FLOWER_NAME POT_SHAPE
POT_ID(FK) POT_COLOR
▶ 객체를 테이블에 맞추어 설계
class Flower {
String flowerId;
String flowerName;
String potId;
// FK는 RDB방식에서의 연관관계이기 때문에 객체방식으로 바꿔야 함.
}
▶ 테이블을 객체에 맞추어 설계
class Flower {
String flowerId;
String flowerName;
Pot pot; // 참조로 연관관계를 맺도록 함.
}
위와 같이 RDB를 객체방식으로 설계하면,
조회 시 JOIN을 하여 FLOWER와 POT에서 각각 필요한 정보를 가져와
각 객체에 담아준 뒤, flower.setPot(pot) 형태와 같이 복잡하게 작업해야 한다.
하지만 만약 자바 컬렉션으로 관리가 가능한다면,
list.add(flower) // 이 때 pot까지 같이 들어감.
Flower flower = list.get(flowerId);
Pot pot = flower.getPot();
훨씬 편하게 작업이 가능하다.
3. 그래프 탐색
Market
│
│
Flower──Pot
│
│
Order──Client
│
│
Delivery
객체는 아래와 같이 모든 객체 그래프를 탐색할 수 있어야 한다.
market.getFlower();
flower.getPot();
...
하지만 SQL 작성 시 이미 탐색 범위가 결정된다.
만약 Market과 Flower를 JOIN해서 조회를 한다면,
market.getFlower()는 사용 가능하지만,
flower.getPot()는 null일 수 밖에 없다.
따라서 엔티티에 대한 신뢰가 무너질 수 밖에 없다.
Market market = marketDAO.find(marketId);
market.getFlower(); // null이 아니라고 확신할 수 없다.
market.getOrder().getClient(); // null이 아니라고 확실할 수 없다.
marketDAO에 있는 find()를 분석해보지 않는 이상 각 엔티티에 대해 신뢰할 수가 없다.
따라서 상황에 따라 조회에 대한 메소드를 여러 개 선언해놓아야 하지만
marketDAO.getFlower();
marketDAO.getMemberWithFlower();
marketDAO.getMemberWithOrderWithClient();
...
모든 객체를 미리 조회해놓는 방법도 사실상 불가능에 가깝다.
4. 값 비교(동일성)
SQL 실행 결과를 담은 뒤 생성자를 호출하여 객체에 담으면 매번 new가 사용되기 때문에 동일한 조회 결과의 객체일 지라도 주소가 모두 다르다.
하지만 만약 자바 컬렉션에서 객체 조회가 가능 하다면
list.get(memberId) == list.get(memberId)
같은 객체를 가져오기 때문에 주소가 같다.
즉, 객체지향으로 설계할 수록 작업이 오히려 복잡해지고 늘어나기 때문에 RDB를 중심으로 설계할 수 밖에 없다. RDB를 자바 컬렉션에 저장하듯 사용하면 굉장히 편해지고 많은 문제가 해결되는데, 바로 이 기술을 JPA(Java Persistence API)라고 한다.
'SPRING' 카테고리의 다른 글
[스터디] 취업뽀개기 사이트 (1) _ N+1 문제 개선 (1) | 2025.07.13 |
---|