주문 검색 기능 개발

-JPA에서 동적 쿼리를 해결방법

 

검색기능

1. 검색 리포지터리 생성

a. OrderSearch 생성 및 정보생성

 

*OrderRepository의 하기 부분을 완성시키기 위한 검색 리포지터리 생성

public List<Order> findAll(OrderSearch orderSearch) { }

 

-파라미터의 조건이 있으면 where문으로 검색이 가능하다.

 

b. OrderRepository에서 OrderSearch 구문 작성

설명

em.createQuery~

-jpql로 작성한다.

-테이블이 아닌 객체로 표현한다. 실제적으로 보면 일반적인 sql join문으로 실행된다.

 

*JPQL이란 <출처:위키백과>

-Java Persistence Query Language

 Java Persistence API 스펙의 일부로 정의 된 플랫폼 독립적인 객체 지향 쿼리 언어

-JPQL은 관계형 데이터베이스에 저장된 엔티티에 대해 조회하는 데 사용

 

값이 다 있다는 가정하에 구문 작성_1

사진 

 

동적쿼리로 변경_2

상태도 다가져오고 네임도 가져오고 createQuery에 있는 내용만 선택을 해야되라고 한다면 동적 쿼리가 된다.

ordersearch에 네임 파라미터 가 없으면 상태값도 선택 되어 있지 않으면 주문이든 주문취소든 다가져와 라고 하려한다면 다음과 같이 작성되어야 한다.

 

사진

 

 

위의 구문을 JPA에서 동적 쿼리로 바꾸어주려면 어떻게 해야 하는가?

JPA에서 동적 쿼리를 어떻게 해결해야 하는가?

 

방법 1 jpql 문자로 무식하게 해결을 한다.

 

 

설명

단점

jpql을 문자로 생성한다는 것은 번거롭고 실수나 버그가 충분히 발생한다.

 

*mybatis를 사용하는 이유가 동적쿼리를 생성하는데 굉장히 편하다는 이점이 있다.

 

JPA Criteria 로 작성 (비권장)_2 -> 실제 포트폴리오에선 이것으로 사용함.

-jpa가 제공하는 jpql를 자바로 작성할 수 있도록 표준인 것이 있다.

 기본편에도 간단하게 설명만 하고 지나갔다.

 

장점

-build하고 나면 결과적으로 jpql이 만들어진다.

-jpql이 자바코드로 작성할 수 있게 jpa criteria가 도와준다.

-동적 쿼리 작성할 때 메리트가 있다.

 

단점

-이것만 봤을 때는 어떤 jpql이 만들어질지 감이 안잡힌다.

 

 

방법 3 QUERYdsl로 작성 (실무에서 권장)

1.Category 엔티티분석 및 카테고리 테이블분석

 

Category 엔티티

-id

-name

-items: List (다대 다 관계)

-parent: Category

-child: List

-상품과 다대다 관계를 맺는다. parent, child로 부모, 자식 카테고리를 연결한 다.

*계층 구조를 이렇게 매핑할 수 있다를 보여주기 위해 이렇게 설정 했다.

*자기자신을 셀프로 계층구조형태로 매핑을 하진 않았을 것 같아 이렇게 설정했다.

 

카테고리 테이블 분석

CATEGORY_ID

-PARENT_ID (FK)

-NAME

 

설명

카테고리와 상품 테이블 분석

-@ManyToMany를 사용해서 매핑한다.

(실무에서 @ManyToMany는 사용하지 말자. 여기서는 다대다 관계를 예제로 보여주기 위해 추가했을 뿐이다)

 

 

2.(Category_Item)중간테이블 및 카테고리와 상품 연관관계 맵핑

 

CATEGORY_ITEM

-CATEGORY_ID (FK)

-ITEM_ID (FK)

 

카테고리 엔티티

-id

-name

-items: List

-parent: Category

-child: List

 

아이템 엔티티

-id

-name

-price : int

-stockQuantity

-categories: List

 

a.카테고리클래스에서 상품과 맵핑

설명

@JoinTable(name = "category_item",
joinColumns = @JoinColumn(name = "category_id),
inverseJoinColumns = @JoinColumn(name = "item_id"))

 

@JoinTable

-객체는 컬렉션이 있어 다대 다관계가 가능하지만

 관계형 DB는 컬렉션관계를 양측에 가질 수 있는 것이 아니기 때문에 1대 다, 다대 1 관계의

 중간테이블을 이용한다.

 

@JoinTable어노테이션

-중간테이블에 있는 외래 키를 매핑 할 때 먼저 사용

 

joinColumns = @joinColumn(name="category_id)

-중간테이블에 있는 category_id 외래키 매핑

 

inverseJoinColumns = @JoinColumn(name = "item_id")

-중간테이블에 있는 item_id 외래키 매핑(item과 연관관계 매핑하기 위함)

 

b.Item클래스에서 카테고리와 맵핑

실습

설명

@ManyToMany(mappedBy ="items")

private List(Category> categories = new ArrayList<>();

 

*foreign key가 있는 items 클래스에 있는 item이 연관관계의 주인이다.

*mapped by - order_item 테이블에 있는 item필드에 의해 맵핑된 거울일 뿐이야라는 뜻

 

주의

실무에서 @ManyToMany는 사용하지 말자.

-실무에서는 다대 다관계로 연관관계를 풀어내지 말 것

-이러한 상태의 테이블만 구현이 가능하고, 다른 필드를 추가하는 것이 불가하다.

 

 

3. 카테고리 구조

 

카테고리가 계층구조로 내려간다.

위의 부모구조 아래에는 자식구조

 

실습

@ManyToOne
@JoinColumn(name ="parent_id")
private Category parent;

@OneToMany(mappedBy = "parent")
private List<Category> child = new ArrayList<>();

설명

-자식 카테고리는 여러개 가질 수 있다.

-셀프로 category안에서 이름만 다를 뿐이지 양방향 연관관계 매핑하듯이 해주면 된다.

 

자 이제 작성한대로 데이터베이스 테이블이 제대로 구성이 되었는지 확인해 보자.

그리고 실제 데이터베이스 테이블구성 및 데이터베이스 명령어 작성/실행

 

실습

create table orders (

order_id bigint not null,

order_date timestamp,

status varchar(255),

delivery_id bigint,

member_id bigint,

primary key (order_id)

);

-> 이것으로 실행시키면 원래 작성했던 코드대로 테이블 구성이 된다.

*JPAalter할 때 작성한 foreign키 컬럼을 전부 잡아준다.

 

참고

foreign key를 꼭 걸어야 되요 안 걸어야 되요?

-시스템마다 다르다.

-실시간 트래픽이 중요하고, 정확성보다는 잘 서비스가 되는 유연한 것이 중요하면

 foreign key를 빼고, 인덱스만 잘 잡아주면 된다.

-하지만, 돈과 관련된 중요한 것이라던가, 데이터가 항상 맞아야 하는 시스템이라면

 foreign key를 넣어주면 된다.

들어가기에 앞서

-예제에서 쉽게 설명하기 위해서 엔티티클래스에 setter getter를 모두 열어두어

 단순하게 설계를 할 것이다.

-실무에서는 getter는 열고, setter는 꼭 필요할 때에만 사용하는 것을 추천한다.

 

1. 회원엔티티개발

 

실습

회원엔티티클래스 생성 및 작성

설명

회원엔티티개발

a. jpabook.jpashopPackagedomain이라고 만든다.

-여기에 핵심 엔티티들을 설치 할 것이다.

 

b. 회원엔티티 작성

-List, ArrayList import class를 해줌

 

c. Address, Order 클래스 파일 생성

 

c. 회원테이블 이름 매핑

-@Id, @generatedValue, @Columns 어노테이션 세팅

 

2.주소값 타입 개발

실습

주소값타입개발

설명

a. address주소 클래스에서 코드작성

@Embeddable 어노테이션 사용

-address 주소가 어딘가에 내장될 수 있게 하기 위해 사용

@Getter 어노테이션을 열어두기

 

b.회원엔티티(RealMember)클래스파일에서 내장타입관련 어노테이션 세팅

-Address변수에 내장타입을 포함했다라는 @Embedded 어노테이션으로 매핑을 해주었다.

-Address변수에 @Embedded 하나만 있어도 되지만,  대개 두가지 어노테이션을 많이 사용한다.

 

3. 주문(order)엔티티클래스파일에서

실습

주문엔티티클래스 생성 및 작성(주문과 회원관계 연관관계매핑)

설명

a.주문엔티티클래스파일에서

-@Entity, @Table 이름 설정을 했다.

-@Table(name = "orders")라고 해주지 않으면

  public class Order에서 Order의 관례로 이름이 Order가 되어 버리기 때문에 이름 설정을 해주어야 한다.

 

b.order_id

-DB컬럼의 id이름을 테이블명으로 가져와 테이블명_id형태로 설정해준다.

 DBA포지션 엔지니어가 이러한 형태로 설정해주는 것을 원한다.

 

참고

엔티티의 식별자는 id를 사용하고 PK 컬럼명은 member_id를 사용했다. 엔티티는 타입(여기서는 Member)이 있으므로 id 필드만으로 쉽게 구분할 수 있다. 테이블은 타입이 없으므로 구분이 어렵다.

그리고 테이블은 관례상 테이블명 + id를 많이 사용한다.

참고로 객체에서 id 대신에 memberId를 사용해도 된다. 중요한 것은 일관성이다.

 

c.@ManyToOne

-주문과 회원의 관계, 다대 1관계를 설정해주는 어노테이션

 

d.@JoinColumn(name = "member_id")

-@JoinColumn 어노테이션은 외래 키를 매핑 할 때 사용

 

e.name 속성에는 매핑 할 외래키(연관관계주인) 이름지정

-member_id = foregien key(외래키)

-주문회원테이블에서 주문회원에 대한 정보를 매핑

 

 

4. 회원엔티티클래스(RealMember)에서

실습

회원엔티티 연관관계 매핑

 

a.어노테이션 설정

@OneToMany

-회원과 주문의 관계, 1대 다 관계를 설정해주는 어노테이션

 

@OneToMany (mapped by = "member")

-foreign key가 있는 order클래스에 있는 member가 연관관계의 주인이다.

-mapped by - order 테이블에 있는 member필드에 의해 맵핑된 거울일 뿐이야라는 뜻

-여기에 무엇을 넣는다고 해서 order에 있는 member필드의 foreign key 값이 변경되지

 않는다.

-order엔티티클래스에 있는 order테이블에 있는 member필드 값을 변경하면

 member_idforeign key 값이 변경된다.

 

어노테이션 설명 참고

https://docs.oracle.com/javaee/6/api/index.html

어노테이션이 궁금하다면 java.persistence -> annotation type을 클릭하면 어노테이션 설명을 볼 수 있다.

 

1.4 연관관계 맵핑 분석

회원과 주문

-회원도 오더로 갈 수 있고, 오더도 회원으로 갈 수 있도록 설계 했다.(양방향 연관관계)

-일대다 , 다대일의 양방향 관계다. 따라서 연관관계의 주인을 정해야 한다.

 관계형데이터베이스에서는 1대 다의 관계에서는 다에 무조건 외래키가 있게 된다.

 외래 키가 있는 주문을 연관관계의 주인으로 정하는 것이 좋다.

 그러므로 ORDERS 엔티티에 있는 MEMBER가 연관관계의 주인이 되고,

 MEMBER엔티티의 ordersmapped by로 단순 읽기만 가능한 연관관계의 거울 즉 단순

 조회용으로만 이용한다.

-연관관계의 주인쪽에 값을 세팅해야 값이 변경된다.

 거울쪽값은 단순조회용이다.

 

-일대다, 다대일의 양방향 관계다. 따라서 연관관계의 주인을 정해야 하는데,

 외래 키가 있는 주문을 연관관계의 주인으로 정하는 것이 좋다.

 그러므로 Order.memberORDERS.MEMBER_ID 외래 키와 매핑한다.

 

*쉽게 얘기하면 주문이 한 개만 있는 것이 아니라 많아질 수 있다고 할 때에

주문쪽에서 PK생성으로 멤버를 참조하여야 하므로 1(MEMBER) (ORDERS)의 관계라고

할 수 있다. 주문측이 갑, 주인이 된다.

 

주문상품과 주문

-한번 주문할 때 주문수량과 주문수량에 따라 가격이 달라질 수 있기 때문에

 주문상품을 두게 된다.

-다른 사람이 주문한 정보가 주문상품에 있을 수 없다.

 주문한상품들이(OrderItem)에는 주문할 때 하나의 Order에만 연관관계가 걸린다.

 주문상품들의 정보들이 OrderItem : List에 오게 된다.

 그래서 다대(ORDERS_ITEM)1(ORDERS)관계가 된다.

 

->다대일 양방향 관계다. 외래 키가 주문상품에 있으므로 주문상품이 연관관계의 주인이다.

   그러므로 OrderItem.orderORDER_ITEM.ORDER_ID 외래 키와 매핑한다.

 

*연관관계 매핑 분석할 때에

-서비스의 특성과 일반적인 관계를 알고, 일반적으로 접근해볼 것

-외래키가 있는 곳이 연관관계의 주인

 

주문상품과 상품

-itemorderitem에서 의 정보를 맵핑 할 것이 없다.

-나를 주문한 orderitem을 찾아 할필요가 없고,

 orderitem을 찾고 싶을 때에 루트를 orderitem으로 쿼리를 찍으면 된다.

 즉, orderitem에서 item정보만 잘 맵핑해주면 된다.

->다대일 단방향 관계다. OrderItem.itemORDER_ITEM.ITEM_ID 외래 키와 매핑한다.

   주문과 배송

-일대일 양방향 관계다. Order.deliveryORDERS.DELIVERY_ID 외래 키와 매핑한다.

-주문정보에 배송정보가 들어가고 OrdersDelivery_ID(PK)가 넣어 두었다.

 

-DELIVERY_ID가 있는 외래키와 매핑하면 Orders가 연관관계의 주인이 된다.

 

카테고리와 상품

-@ManyToMany를 사용해서 매핑한다.

 (실무에서 @ManyToMany는 사용하지 말자. 여기서는 다대다 관계를 예제로 보여주기 위

 해 추가했을 뿐이다)

-편법이 아닌 정상적인 방법으로는 테이블관계는 ManyToMany로 표현할 수 있는 방법이

 없기 때문에, CATEGORY_ITEM 중간테이블로 풀어낸다..

 

카테고리와 상품관련하여 앞에서의 내용과 같은 내용

-객체에서는 카테고리가 아이템리스트를 가져도 되고

 아이템이 카테고리리스트를 가져도 된다.

 양쪽 컬렉션을 만들면 객체는 다대 다로 만들 수 있지만

 관계형데이터베이스는 일반적 설계로는 그렇게 할 수 없다.

 중간에 매핑 테이블(CATEGORY_ITEM)을 두어,

1(CATEGORY) (CATEGORY_ITEM) 관계 및 다대(CATEGORY_ITEM) 1(ITEM)로 풀어

낸다.

 

참고

-외래 키가 있는 곳을 연관관계의 주인으로 정해라.

 연관관계의 주인은 단순히 외래 키를 누가 관리하냐의 문제이지 비즈니스상 우위에 있다고

 주인으로 정하면 안된다..

-예를 들어서 자동차와 바퀴가 있으면, 일대다 관계에서 항상 다쪽에 외래 키가 있으므로

 외래 키가 있는 바퀴를 연관관계의 주인으로 정하면 된다.

 

주의 (연관관계를 잘못 설정하게 되면 생기는 현상)

-물론 자동차를 연관관계의 주인으로 정하는 것이 불가능 한 것은 아니지만,

 자동차를 연관관계의 주인으로 정하면 자동차가 관리하지 않는 바퀴 테이블의 외래 키 값이

 업데이트 되므로 관리와 유지보수가 어렵고, 추가적으로 별도의 업데이트 쿼리가 발생하는

 성능 문제도 있다. 자세한 내용은 JPA 기본편을 참고하자.

 

1-2. 회원 엔티티 분석

1.회원(Member)엔티티

 

회원(Member)

id: Long

-회원엔티티에 공통속성은 id가 다 있다.

-id=pk generating 해주는 id값 데이터베이스

 pk(id)long 값으로 해놓았다.

 

name: String

-이름(string)

 

address: Address

-임베디드 타입(내장값타입)인 주소(Address : 설계도 하기 그림참고-value type address)

 

orders : List

-그리고 주문(orders) 리스트를 가진다.

 

2.주문 엔티티

 

주문(Order)

id

member : Member(회원정보)

orderItems : list (주문목록)

delivery : Delivery(배송정보)

orderDate : Date(주문한날짜)

status : OrderStatus(주문상태-주문,취소 등등)

 

-한 번 주문시 여러 상품을 주문할 수 있으므로 주문과 주문상품(OrderItem)은 일대다 관계 다.

-주문은 상품을 주문한 회원과 배송 정보, 주문 날짜, 주문 상태(status)를 가지고 있다.

-주문 상태는 열 거형을 사용했는데 주문(ORDER), 취소(CANCEL)을 표현할 수 있다.

 

3.주문상품 엔티티

 

주문상품(OrderItem)

-주문한 상품 정보와 주문 금액(orderPrice), 주문 수량(count) 정보를 가지고 있다.

 (보통 OrderLine, LineItem 으로 많이 표현한다.)

-주문상품을 추가한 다른 이유는 한번 주문시 여러 개의 상품을 담을 수 있는데

 주문시점시 주문한 상품의 개수 및 주문한 상품 가격정보가 필요하기 때문이다.

 

4.배송 엔티티

 

배송(Delivery)

id

order : order(주문정보, 배송지주소 아님)

address : Address(배송지주소-value type 값타입 주소를 재활용)

status : DeliveryStatus(배송현황)

 

-배송(Delivery): 주문시 하나의 배송 정보를 생성한다. 주문과 배송은 일대일 관계다.

-주문시 하나의 배송 정보를 생성한다. 주문과 배송은 일대일 관계다.

 

5.상품엔티티

 

상품(Item)

id

name (상품이름)

price: int (상품가격)

stockQuantity (상품재고)

categories: List(어느 카테고리에 매핑 되어 있는지에 대한 정보)

 

상품엔티티와의 상속관계

-상속관계Album, Book, Movie들이 있고,

 개별속성들이 상속관계로 다음과 같이 표현되어 있다.

Album - artist, etc

Book - author, isbn

Movie - director, actor

 

-이름, 가격, 재고수량(stockQuantity)을 가지고 있다.

 상품을 주문하면 재고수량이 줄어든다.

 상품의 종류로는 도서, 음반, 화가 있는데 각각은 사용하는 속성이 조금씩 다르다.

 

6. 카테고리엔티티

 

카테고리(Category)

id

name

items: List(카테고리가 가지고 있는 리스트)

parent: Category

(계층구조로 되어 있다. 내 부모가 누구인데, 자식(속성)은 여러개의 구조로 되어 있다라는 형태, 부모는 한개)

child: List

 

-카테고리(Category): 상품과 다대다 관계를 맺는다. parent, child로 부모, 자식 카테고리를

 연결한다.

 

7. 주소엔티티

 

주소(Address)

-값 타입(임베디드 타입)이다. 회원과 배송(Delivery)에서 사용한다.

 

 

설계구성도는 JPA에서 다룰 수 있는 모든관계개념들을 모두 넣어두었다.

1. MemberOrder - 1대 다 관계

2. Orderdelivery - 11 관계

3. OrderOrderItem - 1대 다 관계

4. OrderItemItem - 다대 1 관계

5. ItemAlbum,Book,Movie - 상속관계

6. CategoryItem - 다대 다 관계

 

실무에서 사용하기 애매한 것들

-Categoryitem의 다대 다 관계(JPA@다대다관계)는 실제운영에서 사용하면 안된다.

 1대 다 또는 다대 1 관계로 풀어내야 한다.

-MemberOrder 1대 다 관계가 아닌, 시스템적으로는 동등한 관계로 보고 고민해야 한다.

-회원을 통해서 주문이 일어난다가 아니라, 주문을 생성할 때 Member가 필요하다라고 생각을 해야 한다.

-쿼리가 일어날 때도 주문 내역이 필요할 때 멤버를 찾아서 거기에 있는 주문 리스트를 가져 오는 것이 아니라,

 order에서도 필터링 조건에 멤버가 들어간다.

-그래서 사실상 1대 다의 컬렉션은 필요없다..

 자세한 것은 기본편강의에서 다루었다.

 

참고

회원이 주문을 하기 때문에, 회원이 주문리스트를 가지는 것은 얼핏 보면 잘 설계한 것 같지만,

객체 세상은 실제 세계와는 다르다. 실무에서는 회원이 주문을 참조하지 않고, 주문이 회원을 참조하는 것으로 충분하다. 여기서는 일대다, 다대일의 양방향 연관관계를 설명하기 위해서 추가했다.

요구사항 확인

-요구사항기반으로 도메인 모델과 테이블 설계

-설계바탕으로 엔티티클래스 개발

-엔티티 설계시 주의점을 알아볼 것

 

간단한 쇼핑몰기능 살펴보기

기능 3가지

 

1. 회원기능

-회원가입(회원등록)

-회원목록(회원조회)

 

2. 상품기능

-상품등록

-상품목록(수정 및 조회)

 

3. 주문기능

-상품주문 및

-주문내역 조회

-주문 취소

 

4. 기타요구사항

-상품은 제고 관리가 필요하다.

-상품의 종류는 도서, 음반, 화가 있다.

-상품을 카테고리로 구분할 수 있다.

-상품 주문시 배송 정보를 입력할 수 있다.

 

6. MemberRepositoryTest파일 테스트

MemberRepositoryTest 파일

설명

@SpringBootTest

-스프링부트로 테스트하기 때문에 SpringBootTest annotation 세팅

 

@RunWith(SpringRunner.class)

-JUnit에게 스프링과 관련된 테스트를 할 것이라고 알려주기 위해 하는 세팅

 

*annotation관련설명

(https://docs.spring.io/spring-boot/docs/2.2.6.RELEASE/reference/html/spring-boot-features.html#boot-features 참고)

If you are using JUnit 4, don’t forget to also add @RunWith(SpringRunner.class) to your test,

otherwise the annotations will be ignored.

If you are using JUnit 5, there’s no need to add the equivalent @ExtendWith(SpringExtension.class)

as @SpringBootTest and the other @Test annotations are already annotated with it.

 

-JUnit4 사용할 경우, @RunWith를 넣지 않으면 annotations들이 적용되지 않을 것이라고 함.

 JUnit5 @SpringBootTest와 같은 annotation을 세팅할필요 없다고 한다.

 

@Autowired MemberRepository memberRepository;

-MemberRepository작동을 위해서 Autowired를 사용해서 MemberRepository 인젝션 받음

 

@Test

-member를 테스트하기 위함

-given when then 형태로 테스트

 

//given

-member 변수를 만들고, memberA로 설정한다.

 

//when

a.member가 잘 저장되는지 확인

: memberRepository.save(member)작성후 save에서 단축키 ctrl+ Alt + v를 누르면

다음과 같은 형태로 설정이 된다.

 

Long saveId = memberRepository.save(member);

-> saveId: 저장된 Id(변수)를 뽑아오는(extract) 역할을 한다.

->member를 가지고 save를 하면 잘 저장이 되는지 확인을 해야 한다.

 

b.Member findmember = memberRepository.find(saveId);

-memberRepository에서 find해서 saveId가지고 넘긴 것이 findmember가 맞는지 확인한다.

*findMember 변수를 만든다.

 

//then (검증)

-Assertions 라고 하면 assertj라는 라이브러리를 스프링테스트가 자동으로 가지고 있어

라이브러리 디펜던시에서 자동으로 올라온다. “ . ”을 찍어주기만 하면!

 

-findMembergetIdmembergetId와 같다.

 findMembergetUsernamemembergetUsername과 같다.

 

#마주한문제

a.applcation.yml_debug설정 위치변경

무엇이 문제인지 정확히 몰라 test하기 위해 연관 있는 파일들을 확인하기 시작했다.

-application.yml 로 들어감

-applcation.yml_debug설정 위치변경

 level : debug 라고 설정이 되어 있음을 확인

 org.hibernate.SQL : debug로 변경

 

b.application.yml_DB경로접속 휴먼에러_JPA에러

-다음과 같은 메시지 확인

a,b 문제해결

그래서 application.yml 들어가니 설정경로가 jap와 debug위치 변경

 

c.MVCC_unsupported 메세지

-MVCC=TRUE 삭제

 

d. URL 에러메세지

-application.yml에서 경로를 확인하니

“ : ” 가 하나 더 추가 되어 있어 삭제

 

 

e. No EntityManager with actual transaction available 에러메세지

엔티티매니저를 통한 모든 데이터 변경 트랜잭션 안에서 이루어져야 하는데

현재 @Transactional 어노테이션이 없다.

2가지 종류의 transaction이 있는데 현재 스프링프레임워크를 사용하므로

-javax.transaction

-org.springframework.transanction <-이것을 사용한다.

 

에러메시지

문제해결

#마주한문제 3_Member테이블 미생성

-H2 콘솔에 접속하여 데이터베이스에 member 테이블이 생겼나 확인하니 Member 생성이 안되어 있었다!

 

a.application.yml_hibernate 단어오타

-hibernate 단어correction

 

b.application.yml에서

-logging.level: 로 다시 변경

-그리고 전체적으로 띄어쓰기가 중요하다는 사실을 발견 전체적으로 2칸씩 이동해줌

-그리고 다시 h2 콘솔 접속하여 데이터베이스에 member테이블생성 확인!

 

문제해결

*localhost:8082로 접속이 안될 시

local에서 h2데이터베이스를 실행시켜주지 않고 실행시킬 시에는

h2.database 관련하여 에러가 나오니 주의 할 것!

cmd에서 h2<bin<h2.bat실행 해주어야 h2데이터베이스로 접속(localhost:8082)접속할 수 있다.

 

 

JPA가 ddl-auto: 에 CREATE 옵션이 있으니 멤버테이블을 만들어 주었다.

member 테이블생성과정

-dropcreate로 테이블 생성을 했다.

-Member Entity정보를 보고 테이블을 생성한다.

 

 

member 테이블에 데이터가 없다?

Transactional이 데이터를 Rollback한다.

-Transactional 어노테이션이 테스트케이스에 있으면 테스트가 끝난 후에 바로 롤백이 되어 버린다.

-테스트케이스가 아닌 곳에서는 제대로 작동된다.

 왜냐하면 데이터가 계속 들어가 있으면 반복적인 테스트를 하지 못하기 때문이다.

 

Rollback(false) annotation

-그럼에도 불구하고 내눈으로 직접 데이터를 보고 싶을 때 이용

JPA 세팅 및 동작 확인완료!

 

기타

-같은 트랜잭션 안에서 저장하고 조회하면 영속성 컨텍스트 같다.

 같은 영속성 context안에서는 id값이 같으면 같은 엔티티로 식별한다.

 같은 영속성 context 안에서 기존 엔티티에서 관리하던 1차 캐쉬에서 바로 정보를 가져온다.

 그래서 select 쿼리는 없고, insert 쿼리만 보인다

a.쿼리 파라미터 로그 남기기 2가지 방법

쿼리 파라미터를 남기는 방법 1

-application.yml ->logging.levvel

org.hibernate.type: trace 추가

쿼리 파라미터를 남기는 방법 2

외부라이브러리 사용

https://github.com/gavlyukovskiy/spring-boot-data-source-decorator

 

-데이터베이스 커넥션을 랩핑해서 왔다갔다하는 만들어진 sql 스테이트먼트를 로그로 출력해주는 라이브러리들을 이용

 

-P6Spy 라이브러리 추가

->build.gradle

-implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.6.1' 추가

->refresh

 

MemberRepositoryTest 실행후

-원본 출력정보 확인 및 파라미터 바인딩 출력정보 확인

-url에서 connection 얻어오는 로그

 

*로그를 어떻게 찍을 건지에 대한 옵션은 상기 사이트에서 확인할 수 있다.

*외부라이브러리 사용시 개발단계에서는 편한데,

 운영단계에서는 성능테스트를 해야 하고 성능저하가 있을 수 있기 때문에,

 성능이 좋지 못하면 개발단계에서만 사용할 것!

 

단어개념_binding Parameter를 보다가

파라미터 - 매개변수

매개변수란

-컴퓨터 프로그래밍에서 매개변수란 변수의 특별한 한 종류로서, 함수 등과 같은 서브루틴의 인풋으로 제공되는 여러

 데이터 중 하나를 가리키기 위해 사용된다. 여기서 서브루틴의 인풋으로 제공되는 여러 데이터들을 전달인자 라고 부른

 다.

 

위키백과 및 구글 참고

https://www.google.com/search?q=%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0&oq=%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0&aqs=chrome..69i57j0l7.1697j0j7&sourceid=chrome&ie=UTF-8

 

바인딩이란

바인딩(binding)이란 프로그램에 사용된 구성 요소의 실제 값 또는 프로퍼티를 결정짓는

행위를 의미합니다.

 

예를 들어 함수를 호출하는 부분에서 실제 함수가 위치한 메모리를 연결하는 것도

바로 바인딩입니다.

이러한 바인딩은 크게 다음과 같이 구분할 수 있습니다.

 

1. 정적 바인딩(static binding)

-실행 시간 전에 일어나고, 실행 시간에는 변하지 않은 상태로 유지되는 바인딩임.

 

2. 동적 바인딩(dynamic binding)

- 실행 시간에 이루어지거나 실행 시간에 변경되는 바인딩임.

이러한 동적 바인딩은 늦은 바인딩(late binding)이라고도 불립니다.

 

참고사이트

http://tcpschool.com/php/php_oop_binding

 

 

다른 라이브러리는 버전정보가 왜 없나요?

기본적으로 스프링부트가 2.1.7에서는 내한테 맞는 라이브러리를 전부 세팅 해놓았따.

미리 세팅 해놓지 않은 라이브러리들은 직접 버전정보를 적어주어야 한다.

 

#마주한문제 <미해결>

jar빌드 동작확인

-windowsmac 환경에 따라 명령어가 다르니 주의!

 

Build

<windows 환경>

jpashop> gradlew.bat

 

<mac 환경>

jpashop> ./gradlew clean build

 

 

Buildjar 라이브러리가 생긴다.

1. resources -> templates -> application.yml생성

yml 또는 properties를 사용하면 된다.

설정파일이 복잡해지면 yml이 더낫다.

여기에서는 application.yml을 생성하고

기존에 있던 application.properties삭제 한다.

 

*YAML이란 (위키백과 참고)

- XML, C, 파이썬, , RFC2822에서 정의된 e-mail 양식에서 개념을 얻어 만들어진

  '사람이 쉽게 읽을 수 있는' 데이터 직렬화 양식

-XMLJSON이 데이터 직렬화에 주로 쓰이기 시작하면서,

 많은 사람들이 YAML'가벼운 마크업 언어'로 사용하려 함

 

*PROPERTIES이란 (위키백과 참고)

-응용 프로그램의 구성 가능한 파라미터들을 저장하기 위해

 자바 관련 기술을 주로 사용하는 파일들을 위한 파일 확장자

-더 복잡한 설정 포맷을 원할 경우 XMLYAML이 사용된다.

 

2. Database connection : 데이터베이스 소스 설정

a. spring 세팅

datasource :

  url: (상기사진내용참고)

  username: sa

  password: 

  driver-class-name: (상기사진내용참고)

(주의: 칸 띄어쓰기가 제대로 되어 맞춰지지 않는다면 테스트시 에러발생할 가능성이 크다!!)

 

설명

application.yml 안에

하기와 같이 설정하게 되면

데이터베이스 연결과 관련된 데이터소스설정이 완료 된다.

[url: jdbc:h2:tcp://localhost/~/jpashop;MVCC=TRUE]

 

*MVCC TRUE

-> 여러개가 접근할 때 조금 더 빨리 처리가 된다. 넣어주는 것이 권장.

*스프링부트에서 hikaricp를 써서 데이터베이스 커넥션 풀 등 위의 세팅이 이루어지게 한다.

 

b. JPA 세팅

 hibernate:

  ddl-auto: create

 properties:

hibernate:

 #show_sql: true

    format_sql: true

 

*createtab을 자동생성해주는 역할을 한다.

application 실행시점에 내가가지고 있는 엔티티(테이블)정보를 전부 다 지우고,

다시 생성한다.

*properties (*hibernate와 관련된 특정한 properties 사용할 것을 여기에다가 타입한다.)

*설정하는 것을 어떻게 배우느냐

spring bootreference document를 참고해서 하나하나씩 공부해야 한다.

https://docs.spring.io/spring-boot/docs/2.2.6.RELEASE/reference/html/

Data Access ->configure JPA Properties를 찾아서 읽어볼 것!

 

c. LOG LEVEL세팅

logging:

   level:

    org.hibernate.SQL: debug

 

(주의 : 잘 안될 경우, logging.level:로 세팅할 것!)

 

*hibernate.SQLdebug모드로 사용한다는 의미가 있고,

jpahibernate가 생성하는 SQL전부 확인이 가능하다.

 

show_sqlorg.hibernate.SQL의 차이점

jpa:

show_sql: true

->system.out에 출력하는 것. 그래서 주석처리를 하여 사용하지 않도록 한다.

운영환경에서는 사용하지 않는다.

 

logging:

org.hibernate.SQL: debug

->log on을 통해 출력하는 것. 운영환경에서는 로그들을 log on을 통해 출력해야 한다.

 

스프링부트란

-복잡하고 어려운 스프링기술을 간결하고 쉽게 사용할 수 있도록 도와주는 기술

 

JPA

-강력한 ORM 기술

-자바진영에서는 두가지 기술의 조합으로 높은 생산성과 맵 어플리케이션을 개발하는 추세

 

목표

-프로젝트를 처음부터 끝까지 코딩으로 완성하는 것이 목표

 

목록

프로젝트 환경설정

-스프링부트

-Gradle

-JPA

-톰캣

-Thymeleaf(타임리프)

-HIBERNATE

 

요구사항 분석

-쇼핑몰 구축을 위한 요구사항 분석

 

도메인설계

-요구사항기반으로

 

엔티티설계

 

테이블설계

 

JPA로 엔티티와 테이블을 ORM으로 맵핑

 

애플리케이션 아키텍쳐 구성

 

핵심비즈니스 로직개발

-테스트케이스로 이것을 검증한다.

 

=>이것들을 하게 되면 도메인 주도 설계를 이해 할 수 있다.

=>이것을 기반으로 웹계층개발을 올린다.

=>컨트롤러 타임리프로 올려서 HTML이 렌더링 되게 만든다.

+ Recent posts