- Spring Data JPA를 통한 데이터 액세스 계층 구현
- Spring Data 패밀리 그룹 : Spring Data JDBC, Spring Data JPA
-> 유사한 사용 방식, PSA(일관된 서비스 추상화)
- JPA : Java 애플리케이션에서 관계형 데이터베이스를 사용하기 위해 정해 놓은 명세
- Hibernate ORM : JPA라는 표준 스펙의 구현체. 실제 사용하는 API.
- Spring Data JPA : Hibernate ORM 등의 구현체를 쉽게 사용하게 해주는 모듈
-> 데이터 액세스 계층 구현 (JDBC와 유사)
1) Repository interface
- CrudRepository를 대신 JpaRepository 를 상속
- JPQL을 통한 객체 지향 쿼리 사용
https://en.wikibooks.org/wiki/Java_Persistence/JPQL
2) 기타 수정 코드
- 데이터 타입을 맞추기위해 직접 수동 매핑 코드 구현 필요
- 과제에서 만든 수동 매핑 코드
@Mapper(componentModel = "spring")
public interface OrderMapper {
Order orderPostDtoToOrder(OrderPostDto orderPostDto);
Order orderPatchDtoToOrder(OrderPatchDto orderPatchDto);
List<OrderResponseDto> ordersToOrderResponseDtos(List<Order> orders);
default OrderResponseDto orderToOrderResponseDto(Order order){
// 새 OrderResponseDto 객체 만들고
OrderResponseDto orderResponseDto = new OrderResponseDto();
// OrderResponseDto 클래스의 각 필드를 할당
long memberId = order.getMember().getMemberId();
List<OrderCoffeeResponseDto> orderCoffees = orderToOrderCoffeeResponseDto(order.getOrderCoffees());
orderResponseDto.setOrderId(order.getOrderId()); //orderId
orderResponseDto.setMemberId(memberId); //memberId
orderResponseDto.setOrderStatus(order.getOrderStatus()); //orderStatus
orderResponseDto.setOrderCoffees(orderCoffees); //orderCoffees
orderResponseDto.setCreatedAt(order.getCreatedAt()); //createdAt
return orderResponseDto;
}
default List<OrderCoffeeResponseDto> orderToOrderCoffeeResponseDto(List<OrderCoffee> orderCoffees){
return orderCoffees.stream()
.map(orderCoffee -> {
return new OrderCoffeeResponseDto(
orderCoffee.getCoffee().getCoffeeId(),
orderCoffee.getCoffee().getKorName(),
orderCoffee.getCoffee().getEngName(),
orderCoffee.getCoffee().getPrice(),
orderCoffee.getQuantity());
}).collect(Collectors.toList());
}
}
- [Spring MVC] 트랜잭션(Transaction)
- Transaction과 ACID 개념은 이전에 공부했음.
https://velog.io/@youngrong/2022.12.01.THU
- 커밋(commit) : 모든 작업을 최종적으로 데이터베이스에 반영하는 명령어. 하나의 트랜잭션 종료
- 롤백(rollback) : 작업 중 문제 발생 시, 트랜잭션 시작 이전으로 되돌아감.
- JPA에서 tx.commit(); 을 통해 커밋이 진행되는 과정은 굉장히 복잡함.
'대략' 아래의 클래스들을 거친다. (읽다가 질림.. 만든 사람들 광기 미쳤다.)
- TransactionImpl
- JdbcResourceLocalTransactionCoordinatorImpl
- AbstractLogicalConnectionImplementor
- JdbcConnection
- Command
- SessionLocal
- 트랜잭션은 데이터베이스에만 한정해서 사용하는 의미는 아님.
-> 전혀 다른 타입의 리소스(데이터베이스, 파일, 메시지 등)를 하나의 작업 단위로 묶어서 처리해야되는 상황 등
- Spring Framework에서의 트랜잭션 처리 -AOP 적용 대상 (부가 기능)
- 로그 레벨 설정 in application.yml
logging:
level:
org:
springframework:
orm:
jpa: DEBUG
- IntelliJ에서 로그 보기 쉽게 만드는 방법(필터링 유용)
https://hsik0225.github.io/intellij/2021/04/12/IntelliJ-GrepConsle/
- 로컬 트랜잭션 (단일 DB) / 분산 트랜잭션 (여러 DB를 하나의 트랜잭션으로 묶어서 처리)
- 선언형 트랜잭션
- 비즈니스 로직에 애너테이션을 추가하는 방식
- @Transactional : 클래스 레벨 or 메서드 레벨
- @Transactional을 클래스 레벨에 추가하면 해당 클래스에서 Repository의 기능을 이용하는 모든 메서드에 트랜잭션이 적용됨.
- 체크 예외(checked exeption)는 @Transactional만 추가해서는 rollback이 되지 않음. catch로 넘어가서 처리되기 때문.
-> catch를 할 필요가 없다면, @Transactional(rollbackFor = {SQLException.class, DataFormatException.class})와 같이 체크 예외를 직접 지정하거나 언체크 예외(unchecked exception)로 감싸서 rollback 가능
- 메서드 레벨에서 @Transactional(readOnly = true)
-> 읽기 전용으로, JPA 내부에서 영속성 컨텍스트를 flush 처리하지 않고, 스냅샷도 생성하지 않음
-> 불필요한 추가 동작 감소. JPA 성능 최적화.
- @Transactional이 클래스 레벨과 메서드 레벨에 함께 적용된 경우
-> 메서드 레벨 적용.
- @Transactional(propagation = Propagation.REQUIRED)
-> 현재 진행 중인 트랜잭션이 존재하면 해당 트랜잭션을 사용하고, 존재하지 않으면 새 트랜잭션을 생성 (디폴트)
-> 여러 클래스의 작업을 하나의 트랜잭션으로 묶음.
https://devlog-wjdrbs96.tistory.com/424
- AOP로 비즈니스 로직에서 트랜잭션 적용 코드 자체를 감추는 방식
- AOP 방식으로 트랜잭션을 적용하기 위한 @Configuration 클래스 정의
- TransactionManager DI
- 트랜잭션 어드바이스용 TransactionInterceptor @Bean 등록
1) new NameMatchTransactionAttributeSource();로 애트리뷰트 소스 생성
2) new RuleBasedTransactionAttribute(); 로 트랜잭션 애트리뷰트 생성
-> .setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); 로 propagation 지정
-> .setReadOnly(true); 추가 설정 가능
3) 트랜잭션을 적용할 메서드에 트랜잭션 애트리뷰트 매핑
-> 트랜잭션 애트리뷰트를 Map에 추가. Map의 key를 메서드 이름 패턴으로 지정
txMethods.put("find*", txFindAttribute);
-> 트랜잭션 애트리뷰트를 추가한 Map 객체를 txAttributeSource.setNameMap(txMethods); 으로 애트리뷰트 소스에 넘김.
4) TransactionInterceptor 객체 생성
-> return new TransactionInterceptor(transactionManager, txAttributeSource);
5) Advisor @Bean 등록
-> pointcut 지정
-> return new DefaultPointcutAdvisor(pointcut, txAdvice());
- 오전 데일리 코딩
- binarySearch(이진탐색 알고리즘(logN)) 해야하는데, 단순 배열 순회(N) 해버리기.. 알고리즘 공부 시급,,
for(int i=0; i<arr.length; i++){
if(arr[i]==target) return i;
}
return -1;
<느낀 점>
어제 처음으로 블로깅 안 했다.
오후 6시 14분부터 14시간 잤음 ;;
요즘 내용이 너무 어려워서 막막하다.
특히 오늘이 역대급이었는데, AOP로 트랜잭션 적용하는 것과 따로 정리는 안 했지만 뒤에 심화로 나온 JTA를 이용한 분산 트랜잭션 적용이 정말 어려웠다.
분산 트랜잭션은 이해 하나도 못 함.
새해부터는 스터디에 들어갈까 생각중이다.
어제까지 수,목 이틀에 걸친 페어 과제는 현재 1번, 2-1번까지 풀었고, 2-2, 2-3 문제를 못 풀었다. 제출 마감은 1월 12일 자정.
새해부터 열심히 해보자.