You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
//JdbcTemplate 추가
//implementation 'org.springframework.boot:spring-boot-starter-jdbc'
//MyBatis 추가
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.0'
//JPA, 스프링 데이터 JPA 추가
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
//H2 데이터베이스 추가
runtimeOnly 'com.h2database:h2'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
//테스트에서 lombok 사용
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
}
application.propeerties
//스프링 부트 3.0 이상
#JPA log
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.orm.jdbc.bind=TRACE
Item - ORM 매핑
packagehello.itemservice.domain;
importlombok.Data;
importjavax.persistence.*;
@Data@Entity//JPA가 사용하는 객체, 엔티티라고 부름publicclassItem{
/** * @Id : 테이블의 PK와 해당 필드를 매핑 * @GeneratedValue(strategy = GenerationType.IDENTITY) : PK 생성 값을 데이터베이스에서 생성하는 IDENTITY 방식 사용(MySQL auto increment) * */@Id@GeneratedValue(strategy = GenerationType.IDENTITY)
privateLongid;
/** * @Column : 객체의 필드를 테이블의 컬럼과 매핑, @Column 생략시 필드 이름을 테이블 컬럼 이름으로 사용 * length = 10 == varchar 10 * */@Column(name = "item_name", length = 10)
privateStringitemName;
privateIntegerprice;
privateIntegerquantity;
publicItem(){}
publicItem(StringitemName, Integerprice, Integerquantity){
this.itemName = itemName;
this.price = price;
this.quantity = quantity;
}
}
JpaItemRepositoryV1
packagehello.itemservice.repository.jpa;
importhello.itemservice.domain.Item;
importhello.itemservice.repository.ItemRepository;
importhello.itemservice.repository.ItemSearchCond;
importhello.itemservice.repository.ItemUpdateDto;
importlombok.extern.slf4j.Slf4j;
importorg.springframework.stereotype.Repository;
importorg.springframework.util.StringUtils;
importjavax.persistence.EntityManager;
importjavax.persistence.TypedQuery;
importjavax.transaction.Transactional;
importjava.util.List;
importjava.util.Optional;
@Slf4j@Repository/** * @Transactional * 1. JPA 모든 데이터 변경(등록, 수정, 삭제)는 트랜잭션 안에서 이루어짐 * 2. 조회는 트랜잭션 없이도 가능, 변경의 경우 일반적으로 서비스 계층에서 트랜잭션 시작하기 때문에 문제 없음 * 3. JPA에서 데이터 변경시 트랜잭션 필수 * */@TransactionalpublicclassJpaItemRepositoryV1implementsItemRepository {
/** * private final EntityManager em : 스프링을 통해 엔티티 매니저 주입 받음 * JPA의 모든 동작은 엔티티 매니저를 통해 이루어짐, 엔티티 매니저는 내부 데이터 소스 가지고 DB에 접근 가능 * */privatefinalEntityManagerem;
publicJpaItemRepositoryV1(EntityManagerem){
this.em = em;
}
/** * JPA가 만들어서 실행한 SQL * insert into item(id, item_name, price, quantity) values (null, ?, ?, ?) * insert into item(id, item_name, price, quantity) values (default, ?, ?, ?) * insert into item(item_name, price, quantity) values (?, ?, ?) * PK 생성 전략을 IDENTITY 로 사용, Item 객체의 id 필드에 데이터베이스가 생성한 PK 값 들어감 * */@OverridepublicItemsave(Itemitem){ //저장em.persist(item);
returnitem;
}
/** * update() 수정 * JPA가 실행할 SQL : update item set item_name=? , price=?, quantity=?. where id=? * em.update() 같은 메서드 호출이 없어도 실행되는 이유 * JPA는 트랜잭션이 커밋되는 시점에, 변경된 엔티티 객체가 있는지 확인, 변경된게 있으면 UPDATE SQL 실행 * */@Overridepublicvoidupdate(LongitemId, ItemUpdateDtoupdateParam){ //수정, 변경ItemfindItem = em.find(Item.class, itemId);
findItem.setItemName(updateParam.getItemName());
findItem.setPrice(updateParam.getPrice());
findItem.setQuantity(updateParam.getQuantity());
}
@OverridepublicOptional<Item> findById(Longid){ //조건 검색Itemitem = em.find(Item.class, id);
returnOptional.ofNullable(item);
}
/** * JPQL : JPA는 JPQL 이라는 객체지향 쿼리 언어 제공, 여러 데이터를 복잡한 조건으로 조회할 때 사용 * 실행된 JPQL * select i from Item i where i.itemName like concat('%',:itemName,'%') and i.price <= :maxPrice * JPQL을 통해 실행된 SQL select item0_.id as id1_0_, item0_.item_name as item_nam2_0_, item0_.price as price3_0_, item0_.quantity as quantity4_0_ from item item0_ where (item0_.item_name like ('%'||?||'%')) and item0_.price<=? * */@OverridepublicList<Item> findAll(ItemSearchCondcond) { //모두 검색Stringjpql = "select i from Item i";
IntegermaxPrice = cond.getMaxPrice();
StringitemName = cond.getItemName();
if (StringUtils.hasText(itemName) || maxPrice != null) {
jpql += " where";
}
booleanandFlag = false;
if (StringUtils.hasText(itemName)) {
jpql += " i.itemName like concat('%',:itemName,'%')";
andFlag = true;
}
if (maxPrice != null) {
if (andFlag) {
jpql += " and";
}
jpql += " i.price <= :maxPrice";
}
log.info("jpql={}", jpql);
TypedQuery<Item> query = em.createQuery(jpql, Item.class);
if (StringUtils.hasText(itemName)) {
query.setParameter("itemName", itemName);
}
if (maxPrice != null) {
query.setParameter("maxPrice", maxPrice);
}
returnquery.getResultList();
}
}
JpaConfig
packagehello.itemservice.config;
importhello.itemservice.repository.ItemRepository;
importhello.itemservice.repository.jpa.JpaItemRepositoryV1;
importhello.itemservice.service.ItemService;
importhello.itemservice.service.ItemServiceV1;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importjavax.persistence.EntityManager;
@Configuration//Spring 설정 클래스 정의된 메서드는 @Bean을 통해 스프링 빈으로 등록publicclassJpaConfig{
privatefinalEntityManagerem; //JPA에서 데이터베이스와 상호작용을 위한 객체publicJpaConfig(EntityManagerem){
this.em = em;
}
@Bean//스프링 빈으로 등록publicItemServiceitemService(){
returnnewItemServiceV1(itemRepository());
}
@BeanpublicItemRepositoryitemRepository(){
returnnewJpaItemRepositoryV1(em);
}
}
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
JPA
ORM
JPA는 애플리케이션과 JDBC 사이에서 동작
JPA 동작 - 저장
JPA 동작 - 조회
JPA와 CRUD
JPA 설정
build.gradle
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
}
application.propeerties
Item - ORM 매핑
JpaItemRepositoryV1
JpaConfig
JPA 예외 변환
@repository 기능
결과
리포지토리에 @repository 애노테이션만 있으면 스프링이 예외 변환 처리하는 AOP 만들어줌
예외 변환 전
예외 변환 후
All reactions