*간단 개념

 

ORM

 ORM 이란 Object-Relational Mapping 의 약자로, 이름 그대로 객체(Object)와 관계형 데이터(Relational data) 를 매핑하기 위한 기술이다. 객체와 테이블 관계를 바탕으로 SQL문장을 자동으로 생성하여 객체로 DB를 조작하게 하는 기술.

객체 지향 프로그래밍과 관계형 데이터베이스 사이의 목표와 동작 방식이 다르다 보니 데이터 표현 방식이 달라서 패러다임 불일치가 일어나는데, 이 때문에 개발자는 더 많은 코드를 작성해야하고 실수하기 쉬운 것은 ORM이 해결해준다. 

 

JPA

JPA는 Java Persistence API의 약자로, 자바 ORM 기술에 대한 API 표준 명세이다. ORM을 사용하는 방식을 정의한 인터페이스를 모아둔 것. JPA는 특정 기능을 하는 라이브러리가 아니며, 말그대로 인터페이스이다. 따라서 사용방식에 대해서만 정의했을 뿐 구현이 없다.

 

Hibernate

JPA라는 명세의 구현체. 즉, JPA 인터페이스를 구현한 라이브러리 중 하나로 현 프레임워크 중 가장 주도 하고 있다.

 

Spring Data JPA

Spring Data JPA는 JPA를 쓰기 편하게 만들어놓은 모듈이다. JPA를 한 단계 추상화시킨 Repository라는 인터페이스를 제공함으로써 JPA를 사용할 때 예상가능하고 반복적인 코드들을 대신 작성해주어 코드를 줄일 수 있도록 해준다.  

내부적으로 Hibernate를 사용하고 있다.

 

 

 

 

[Spring] Spring Data JPA 이해하기 (feat ORM, JPA)

🌱 ORM 이란? ORM 이란 Object-Relational Mapping 의 약자로, 이름 그대로 객체(Object)와 관계형 데이터(Relational data) 를 매핑하기 위한 기술이다. 이러한 매핑이 필요한 이유는 객체 지향 언어과 관계형 데

doing7.tistory.com

 

 

01. 기본 엔티티 매핑 관련

기본 엔티티 매핑에 조금 더 디테일한 설정들

@Entity 
@Table (name="USER") 
public class Member { 
	
	@Id 
	@Column (name = "user_id") 
	private String id; 
	 
	private String username; 
	
	private Integer age; 

	@Enumerated (EnumType. STRING) 
	private RoleType userRole;

//	@Enumerated (EnumType. ORDINAL) 
//	private RoleType userRole;

	@Temporal (TemporalType. TIMESTAMP) 
	private Date createdDate;

	@Temporal (TemporalType. TIMESTAMP)  
	private Date modifiedDate;
 
}
어노테이션 추가 설명
@Entity - 기본 생성자는 필수, 매개값이 있는 생성자가 있다면 Java는 기본 생성자를 생성해주지 않기 때문에 기본으로 생성해준다.
- final 클래스, enum, interface, inner class엔 사용할 수 없다
- 저장할 필드라면 final을 사용하면 안된다.
@Table 엔티티와 매핑할 테이블 이름 
생략 가능한 경우 : 엔티티의 이름을 테이블 이름으로 사용한 경우
@Column 객체 필드를 테이블 컬럼에 매핑 (생략 가능)
@Enumerated Java Enum을 테이블에서 사용하는 방식

 


02. 연관 관계 관련 심화

 

  • 단방향 연관관계 @ManyToOne 

다대일(N:1)의 관계 매핑

예시)

@Entity
@Getter
@Setter
public class Member {
	@Id
	@Column(name = "member_id")
	private String id;
	private String username;
	
	@ManyToOne			// Many가 Member, One이 Team
	@JoinColumn(name="team_id")	// 연결할 Entity class의 id이름
	private Team team;              // 연결할 Entity class

	public void setTeam(Team team) {
		this.team = team;
	}
}

@Entity
@Getter
@Setter
public class Team {
	@Id
	@Column (name = "TEAM_ID")
	private String id;
    
	private String name;
}

 

  • 양방향 연관관계 

3가지 Entity를 가지고 관계 보여주는 예시) 

 

Member Entity @OneToMany - 멤버는 여러 주문을 할 수 있다.

더보기
@Getter
@Entity
@NoArgsConstructor
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(nullable = false)
    private String memberName;

	// One이 Member, Many가 Orders 멤버는 여러 주문을 할 수 있기 때문
    // 
    @OneToMany(mappedBy = "member", fetch = FetchType.EAGER)
    private List<Orders> orders = new ArrayList<>();

    public Member(String memberName) {
        this.memberName = memberName;
    }
}

Food Entity @OneToMany - 음식은 여러 주문에 들어갈 수 있다.

더보기
@Getter
@Entity
@NoArgsConstructor
public class Food {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(nullable = false)
    private String foodName;
    @Column(nullable = false)
    private int price;

    @OneToMany(mappedBy = "food",fetch = FetchType.EAGER)
    private List<Orders> orders = new ArrayList<>();

    public Food(String foodName, int price) {
        this.foodName = foodName;
        this.price = price;
    }
}

Orders Entity @ManyToOne - 주문하나에 음식하나, 멤버하나를 가질 수 있어 각각 ManyToOne

더보기
@Getter
@Entity
@NoArgsConstructor
public class Orders {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "food_id")
    private Food food;

    @ManyToOne
    @JoinColumn(name = "member_id")
    private Member member;

    public Orders(Food food, Member member) {
        this.food = food;
        this.member = member;
    }
}

 

  • 방향의 차이 

단방향이든 양방향이든 두 예시에서 보면  Many쪽은 큰 차이가 없다. 데이터 베이스는 다를까? 데이터 베이스도 차이가 없다. 애초에 데이터베이스는 양방향이 기본이기 때문에 외래키는 양방향에서 조회가 가능하기 때문이다.

(ManyToMany는? 다대다 관계는 애초에 사용을 지양해야한다. 다대다 관계를 정규화를 통해 일대다 혹은 다대일로 중간 테이블을 두어 풀어 사용해야한다. 실무에서는 절대로 사용하면 않는다고 한다.)

// Member의 Team쪽
@ManyToOne
@JoinColumn(name="team_id")
private Team team;
// Order의 Member쪽
@ManyToOne
@JoinColumn(name = "member_id")
private Member member;

 

그렇다면 Many의 반대쪽은 어떨까

@OneToMany(mappedBy = "member", fetch = FetchType.EAGER)
private List<Orders> orders = new ArrayList<>();

형식이 좀 다른데 One mappedBy 속성을 잘 이해해야 한다. mappedBy에는 반대쪽 매핑의 필드 이름을 값으로 주면 되는데 여기서 연관관계의 주인이라는 개념이 나온다.

 

  • 연관관계의 주인? 

원래 객체에서의 양방향관계는 엄밀히 말하자면 서로 다른 단방향 연관관계 2개다.

아래 표와 같이 서로 다른 단방향을 로직으로 잘 묶어 양방향인 것 처럼 보이게 한 것 뿐이다.

 

데이터베이스의 테이블의 외래키는 하나만 있으면 되는 차이가 있다.

때문에 객체에서는 참조가 양쪽에서 각각 하나씩 참조해 2개인데 DB의 테이블의 외래키는 두 테이블 사이에 1개 뿐이면 된다.

객체의 연관관계 테이블의 연관관계
Member → Team Member ↔ Team
Team → Member

이런 차이로 JPA는 테이블과의 연관관계 처럼 두 테이블 중 하나에 외래키 하나를 두는 것 처럼 두 객체 연관관계 중 하나를 정해서 테이블의 외래키를 관리해야하는 데 이를 연관관계의 주인(Owner)라고 한다.

 

연관관계는 둘 사이에 한쪽을 연관관계의 주인으로 정해야한다. 연관관계의 주인만이 데이터 베이스 연관관계와 매핑되고 외래 키를 관리(등록, 수정, 삭제) 할 수 있기 때문이다. 반대로 주인이 아니면 읽기만 할 수 있다. 연관관계의 주인 = 외래키 관리자 인 것이다.

연관관계를 설정할 때 주인은 주인답게 별도의 mappedBy속성을 사용하지 않고 주인이 아닌쪽이 mappedBy속성을 사용해 속성값으로 이 연관관계인 주인님의 필드을 지정한다. (주인님!)

 

 

 

JPA 05.02 - 양방향 연관관계와 연관관계의 주인

양방향 연관관계 이제 팀에서도 회원으로 접근할 수 있도록 양방향 연관관계로 매핑해 보겠습니다. 먼저 객체 연관관계를 살펴보겠습니다. 회원과 팀은 다대일 관계이며 반대로 팀에서 회원은

delusidiot.tistory.com

 

 

  • 양방향 연관 관계의 주의점 

연관관계 주인에 값을 입력하지 않고, 주인이 아닌 entity에 값을 입력하면 문제가 생길 수 있다. 

Order order = new Order ("order", "order”);
em.persist(order);

Order order2 = new Order (”order2", "order2”);
em.persist(order2);

Member member = new Member("member", ”member”);

//여기가 실수 포인트!!! 
member.getOrders().add(order);
member.getOrders().add(order2);
em.persist(member);

 

member.order에만 값을 저장하고 order.member에 아무 값도 입력하지 않았다면 외래키 값도 null로 저장되는 상태가 된다.

이런 문제를 해결하는 방법은 객체 관점에서는 양쪽 방향에서 모두 값을 입력해주는 것이 가장 안전하다. 

하지만 매번 양쪽으로 값을 넣는 건 깜빡할 여지가 많아 이런 식으로 메소드를 만들어 양쪽에 저장해 주는 방식도 있다.

private Order order;
  public void setMember(Member member) {
    this.member = member;               // order.member에 저장
    member.getOrders().add(this);	// member.order에 저장
  }
  ...
}

 

 

'Programming > Spring' 카테고리의 다른 글

스프링 부트(Spring Boot) 다운 그레이드  (0) 2022.12.07
ORM / JPA / Hibernate / Spring Data JPA  (0) 2022.12.05
영속성 컨텍스트  (0) 2022.12.02
Spring Annotation 정리  (0) 2022.11.30
의존성과 라이브러리  (0) 2022.11.28

 

영속성 컨텍스트 (Persistence Context) 정의

 

영속성 컨텍스트란 엔티티를 영구 저장하는 환경. 어플리케이션이 데이터베이스에서 꺼내온 데이터 객체를 보관하는 역할을 하는 환경을 의미한다.

 

  • 엔티티 매니저 

영속성 컨텍스트를 관리하는 관리자.

특정 작업을 위해 데이터베이스에 접근하고 엔티티를 CRUD하는 역할 및 엔티티 관련 일을 처리하는 관리자이다.  엔티티 매니저를 통해 엔티티를 조회하거나 저장할 때 엔티티를 보관하고 관리한다. 엔티티 매니저마다 따로 공간을 가진다.

 

  • 엔티티 매니저 팩토리 

스레드가 하나 생성 될 때 마다 엔티티 매니저를 생성한다.

엔티티 매니저에 여러 스레드가 동시 접근하여 동시성 문제가 발생하기 때문에 엔티티 매니저를 공유하면 안되는데 엔티티 매니저 팩토리가 통해서는 여러 스레드가 동시 접근할 수 있게 해준다.

다만, 엔티티 매니저 팩토리는 설정 정보를 읽어와 DB 커넥션 풀도 생성하기 때문에 생성하는 데 굉장히 큰 비용이 든다. 따라서 어플리케이션 전체에 하나만을 생성하여 공유해 사용해야 한다.

 

 

 

출처 자바 ORM 표준 JPA - https://product.kyobobook.co.kr/detail/S000000935744

 

 


영속화 한다

엔티티 매니저가 자기의 영속성 컨텍스트에 넣어 관리한다는 의미

 

 


JPA의 엔티티 생명주기 상태

  • 비영속(New (새로운) / Transient (일시적인)) 

영속성 컨텍스트와 관계가 없는 새로운 상태로 이 상태 객체의 데이터 생성 및 변경은 DB와 관련없고 그저 Java 객체로써 존재.

// 엔티티를 생성
Member member1 = new Member();
member.setId("id123");
member.setName("이순신");

 

  • 영속(Managed) 

엔티티 매니저를 통해 엔티티가 영속성 컨텍스트에 저장되어 관리되는 상태. 이 상태 객체의 데이터가 생성되거나 변화되면 JPA가 이를 추적하면서 필요에 따라 DB에 반영한다.

entityManager.persist(member1);

 

  • 준영속(Detached) 

관리되다가 영속성 컨텍스트에서 분리된 상태

// 엔티티를 영속성 컨택스트에서 분리
entityManager.detach(member1);
// 영속성 컨텍스트를 비우기
entityManager.clear();
// 영속성 컨택스트를 종료
entityManager.close();

 

  • 삭제(Removed) 

영속성 컨텍스트에서 삭제된 상태

entityManager.remove(member1);

 

 


영속성 컨텍스트의 이점

 

  • 1차 캐시 

DB를 이용하는 작업은 부하가 심한 작업이기 때문에 자주하는 것을 줄여야 할 필요가 있다.

그래서 매번 DB의 데이터를 얻기위해 DB와 직접 쿼리를 날려 작업하는 걸 줄이기 위해 DB에서 가져온 데이터를 임시로 저장하는 "1차 캐시"를 영속성 컨텍스트 내부에 두게 된다.

JPA에서 1차 캐시를 이용하는 과정은 아래와 같다

 

    1. find("이순신")와 같은 로직이 있을 때 먼저 1차 캐시를 조회

    2-1. 1차 캐시 안에서 있으면 해당 데이터 반환

    2-2. 1차 캐시에 없으면 실제 DB로 해당 쿼리를 보낸다

    3. 해당 결과를 반환하기 전 1차캐시에 저장하고 반환

 

단, 1차 캐시는 해당 Transaction과 생명주기가 같다는 단점이 있다. 

 

  • 쓰기 지연 SQL 저장소 

트랜잭션을 지원하는 쓰기 지연(Transactional Write-behind)의 가장 큰 장점은 데이터베이스 테이블 로우에 락이 걸리는 시간을 최소한다.

쓰기 지연을 사용하지 않고 그때 그때 SQL을 직접 다루면 UPDATE SQL을 실행할 때 마다 테이블 로우에 락이 걸린다.

하지만 쓰기 지연을 사용하면 트랙잭션이 커밋되기 전까지의 SQL을 쌓아두고 있어 트랜잭션 진행 중에 데이터 베이스 로우에 락을 걸지 않고 커밋된 순간에만 해당 로우에 락을 걸어 시간을 최소화 한다. 따라서 동시에 더 많은 트랙잭션을 처리 할 수 있게 한다.

 

    1. 엔티티를 영속화할때 엔티티를 1차 캐시에 저장

    2. 쓰기 지연 SQL 저장소에 insert SQL을 저장하여 쌓아둔다

    2. entityManager.commit() 메소드 호출 

    3. 내부적으로 지연 SQL 정장소에서 Flush (변경 내용을 데이터 베이스에 동기화) 가 일어난다

    4. "Insert A", "Insert B"와 같은 쓰기 전용 쿼리들이 DB로 흘러가 반영된다. 

 

  • DirtyChecking(변경 감지) 

데이터의 변경을 감지해 자동으로 수정한다.

1차 캐시에는 DB의 엔티티의 정보만 저장하는 것이 아니라 해당 엔티티를 조회한 시점의 데이터 정보를 같이 저장해둔다. 

엔티티객체와 조회 시점의 데이터가 달라졌다면 변경이 발생했다는 걸 인지하고 해당 변경 부분에 대한 Update 쿼리를 작성해 쓰기 지연 SQL 저상소에 넣어둔다. 

 

    1. 트랜잭션을 commit하면 엔티티 매니저 내부에서 먼저 flush 호출

    2. 엔티티와 *스냅샷을 비교해서 변경된 엔티티를 검색

    3. 변경된 엔티티가 있으면 변경 부분에 대한 Update 쿼리를 생성해서 쓰기 지연 SQL 저장소에 저장

    4. commit()이나 flush()가 일어나면 쓰기 지연 저장소의 SQL을 데이터베이스에 전송

    5. 데이터베이스 트랜잭션을 commit 하여 반영

 

+ 엔티티를 영속성 컨텍스트에 보관할 때, DB의 엔티티에 조회하여 가져온 최초 상태를 복사해 저장해 둔걸 스냅샷이라고 한다. 그리고 플러시 시점에서 스냅샷과 엔티티를 비교해 변경된 엔티티를 찾는다.

+ 주특기입문 과제때 업데이트를 하면서 save와 같은 메서드를 호출하지 않았는데도 변경되었던 걸 생각하면 된다. 

 

  • 데이터의 어플리케이션 단의 동일성 보장 
Member member1 = em.find(Member.class, "minsook");
Member member2 = em.find(Member.class, "minsook");
System.out.println(member1 == member2) => true

 

위의 Member1와 Member2를 == 비교를 하게되면 같다는 결과가 나온다.

JPA는 영속 엔티티의 동일성을 보장해주는데 java 컬렉션에서 값을 가져 올때 동일한 주소 값을 가져오듯이, 같은 reference를 불러오면 같은 1차 캐시 안에서 값을 가져와 동일성을 보장하는 것이다. 

 

 

 

 


참조 링크들: 

 

3.영속성 관리 · jpa

 

ultrakain.gitbooks.io

 

1. 엔티티 (Entity) 와 엔티티 매니저 (Entity Manager)

엔티티 매니저 특정 작업을 위해 데이터베이스에 액세스하는 역할을 담당한다. 엔티티를 DB 에 등록/수정/삭제/조회(CRUD) 하는 역할이며, 엔티티와 관련된 일을 처리하는 엔티티 관리자이다. - 엔

lhwn.tistory.com

 

[JPA] 영속성 컨텍스트

JPA에서 가장 중요한 2가지 아래와 같다.객체와 관계형 데이터베이스 매핑영속성 컨텍스트JPA를 이해하는데 가장 중요한 용어엔티티를 영구 저장하는 환경 이라는 뜻EntityManager.persist(entity);데이

velog.io

 

JPA 플러시 정리 - Yun Blog | 기술 블로그

JPA 플러시 정리 - Yun Blog | 기술 블로그

cheese10yun.github.io

 

 

* 수시로 업데이트 할 예정

 

  • 실행
@SpringBootApplication 스프링부트가 실행될 기준이될 클래스, main메소드가 선언된 곳에 선언해준다.

 

  • 생성자
@NoArgsConstructor 파라미터가 없는 기본 생성자를 생성
@RequiredArgsConstructor final변수, Notnull 표시가 된 변수 등 필수적인 정보를 세팅하는 생성자를 생성
@AllArgsConstructor 전체 변수를 생성하는 생성자

 

  • 필드
@Getter Class 내의 모든 필드의 Getter method 생성
@Setter Class 내의 모든 필드의 Setter method 생성

 

  • Controller
@Controller 기본 컨트롤러 선언
@Component포함
@RestController @Controller + @ResponseBody
이 어노테이션을 사용하면 별도의 @ResponseBody를 선언해줄 필요 없다.
@Component포함

 

  • Service
@Service @Component포함

 

  • Repository
@Repasitory JpaRepository를 상속할 경우 JpaRepository를 통해 빈으로 등록 

 

  • Entity
@Entity 테이블과 매핑 
name =  엔티티 이름 설정. HQL에서 엔티티 식별할 이름
@Table 엔티티와 매핑할 테이블을 지정. 생략시 매핑한 엔티티 이름을 테이블 이름으로 사용
name =  매핑할 테이블 이름 (default. 엔티티 이름)
ctalog =  catalog 기능이 있는 DB에서 catalog를 매핑
(default. DB이름)
schema =  schema기능이 있는 DB에서 schema를 매핑
uniqueConstraints = *DDL 생성시 유니크 제약 조건 생성
스키마 자동 생성 기능을 사용해 DDL만들 때만 사용
@UniqueConstraint    
@Data    
@Id entity의 id임을 선언
@GeneratedValue 값 자동 생성 
strategy = GenerationType.
(생성 전략) 
AUTO (자동) (✅ default)
IDENTITY 
(id값을 먼저 insert 해버려 트랜젝션이 끝나기 전에 , 즉 롤백 된다하더라도 이미 insert 되어 있어서 마치 이빨빠진것 처럼 중간에 비는 현상이 발생한다.)
SEQUENCE
(오라클, postqre에서 쓰는데 insert를 할 때 sequence로부터 증가된 id 값을 받아서 실제 id값에 넣는 방식)
TABLE
(DB종류 상관없이 테이블에 id값을 저장해 추출하여 사용)
@Column 객체 필드를 테이블 컬럼에 매핑 (생략 가능)
nullable (null값 허용) = true / false
name =  매핑할 컬럼 이름 (default. 변수 이름)
@Enumerated Java Enum을 테이블에서 사용하는 방식
EnumType. ORDINAL 
(enum 순서를 DB에 저장) (✅ default)
STRING
(enum 이름을 DB에 저장, 후에 enum이 변경되어도 문자열 그대로 저장되어있어 변경되어도 위험이 없어 일반적으로 string을 사용)
@EntityListeners 삽입, 삭제, 수정, 조회 등의 작업을 할 때 전, 후에 어떠한 작업을 하기 위해 이벤트 처리를 위한 어노테이션
AuditingEntityListener.class Audit(감시하다) 옵션은 시간에 대해서 자동으로 값을 넣어 주는 기능
@ManyToOne 다대일(N:1) 관계 매핑, 연관관계의 주인임을 나타낸다.
optional false 설정 시 연관된 엔티티가 항상 있어야 한다.
(default. true)
fetch = FetchType.
(global fetch 전략 설정)
EAGER (즉시로딩)
LAZY (지연로딩)
cascade = CascadeType.
(영속성 전이 기능 사용)
ALL
(모든 부분에서 영속성 전이)
PERSIST 
(부모 영속화시 연관된 자식들도 영속화)
MERGE
REMOVE
REFRESH
DETACH
orphanRemoval  
@JoinColumn 외래 키 매핑 (생략가능)
name =  외래 키로 연결할 컬럼 이름
@OneToMany 일대다(1:N) 관계 매핑
mappedBy = 연관관계 주인 설정

 

  • 상속
@MappedSuperclass 공통 매핑 정보가 필요할 때, 부모클래스에 선언하는 어노테이션. 필드만 상속 받아서 사용 하고 싶을때 사용.

 

  • Bean
@Component    
  @Autowired 스프링에 의해 생성된 Bean객체를 DI (의존성 주입)

 

 

 

 

 


참고 링크들 :

생성자 관련 ) https://goyunji.tistory.com/98

Entity 관련) https://data-make.tistory.com/610

 

* 간단 개념만 정리

 

의존성 (Dependency) 란? ) 

사용하는 방법을 보면 라이브러리 == dependency ? 라는 의문이 생긴다. 라이브러리를 사용하는데 왜 dependency를 추가하는 것이라고 할까.

 

클래스 A가 다른 클래스  또는 인터페이스 B를 사용할 때 A가 B에 의존하는 관계가 된다.

B가 없으면 작동할 수 없는 A를 dependant라고 하며, 의존의 대상이 되는 B를 dependency라고 한다. 

또한 의존대상 B가 변하면 그것이 A에 영향을 미친다. 

 

코드를 짤 때 작성한 클래스가 라이브러러의 기능을 사용하게 되면 라이브러리에 의존하게 되므로 라이브러리는 dependency가 되며, 작성한 클래스는 dependant가 된다. 

그래서 dependency와 라이브러리가 같은 것 이라고 할수 없지만

라이브러리를 사용하는것이 dependency 즉, 의존성을 늘리게 되는 행동이기 때문에 라이브러리를 사용하는 것을 dependency를 추가한다고 표현하는 것이다. 

 

 

의존성이란

어떤 클래스A가 다른 클래스 또는 인터페이스B를 이용할때 A가 B에 의존한다고 한다.A는 B없이 작동할 수 없고 B를 재사용하지 않으면 A또한 재사용할 수 없다.이러한 상황에서 클래스A를 dependant

velog.io

 

 

 


build.gradle 파일에서 사용 중인 플러그인, dependencies 등을 확인할 수 있다.

 

 

위의 dependencies 리스트와 실제로 사용중인 라이브러리의 리스트가 일치하지 않는다.

 

왜냐하면 우리가 Spring Web이 필요해서 이것만 끌어온다고 선택했지만 Spring Web이 또 의존하고 있는 라이브러리들을 존재한다. 결국 Spring Web을 사용하려면 이런저런 라이브러리들을 더 끌고 와야해서 실제적으로는 아래처럼 수많은 라이브러리들을 끌고 오게 되고 마지막엔 spring-core까지 끌고 오게 된다. 

 

 

라이브러리의 관계성을 보고자 하면, 

하늘 색으로 표시되는, 창을 둘러싼 메뉴들 중 오른쪽 메뉴 들 중에서 Gradle을 찾아 눌러 라이브러리를 확인할 수 있는데 

 

 

펼쳐보면 수많은 라이브러리들에 의존하고 있는 걸 볼 수 있다. 이게 전부 끌려온 것이다. 

+ 참고로 (*)가 붙은건 이미 다른 라이브러리에서 이와 같은 걸 의존하고 있어 중복되어 있으므로 생략했다는 뜻이다.

 

 

 

 

이번 강의 라이브러리 관련 Tip
+ 현업에서는 System.out.print를 사용안하고 로그로 확인하며 에러를 관리한다.
로깅에 관련한 라이브러리가 궁금하다면, logback과 slf4j에 대해 검색해보자.
+ 자바 진영에서는 테스트 프레임워크로 junit을 사용

 

+ Recent posts