본문 바로가기

Back-End

(91)
트랜잭션 전파 속성 ( propagation ), 롤백 예외 트랜잭션을 시작하거나 기존 트랜잭션에 참여하는 방법을 결정하는 속성이다. 트랜잭션 경계의 시작 지점에서 트랜잭션 전파 속성을 참조해서 해당 범위의 트랜잭션을 어떤 식으로 진행시킬지 정할 수 있다. 이렇게 글로만 보면 트랜잭션 전파 속성은 왜 써야하는지 전혀 와닿지 않는다. 항상 필요에 의한 공부를 할 때 진정한 공부가 되는 것 같다. e-커머스 회사를 다니고 있고, 고객 주문 + 주문 내역을 기록해주는 기능을 개발하라고 지시를 받았다! 어떻게 개발할 것인가? 트랜잭션을 어떻게 묶을까? 위의 상황을 분석해보면, 고객 주문은 성공을 했는데 주문 내역이 기록이 되지 않아 롤백된다면??? 이 얼마나 매출을 깍아먹는 개발자인가.... 즉 지금 상황에서 트랜잭션을 어떻게 묶을지 결정할 수 있는 요인은 중요한 일(주..
대용량 트래픽을 감당하기 위한 Spring WebFlux 도입 프로모션 기간이나 이벤트 기간에 유저가 폭발적으로 늘어난다면? 어떻게 처리할것인가? 이런 질문을 받는다면 어떻게 접근할 것인가? DB I/O 를 줄이기 위해 캐시? JPA 쿼리 최적화?? 이렇게만 접근했다면 Spring MVC + RDBMS 개발에만 너무 한정되어 있었다고 생각한다. ( 내 얘기이다... ) 물론 해당 방법으로 접근해도 개선이 되는것은 맞다. Blocking I/O 우리가 가장 일반적으로 프로그래밍하는 모델이다. Application에서 I/O 요청을 하고 끝날때까지 Block 되어 다른 작업을 수행할 수 없다. 하지만 Spring Web Application 개발을 하면 Tomcat이나 Netty가 Multi Thread 기반으로 동작하기 때문에 Block 안된듯이 동작한다. 이렇게 되..
Redis Spring Boot에 설정하기 및 개요 Redis, Cache 는 왜 사용하는걸까? 백앤드 개발을 하다보면 가끔 조회하는 시간 때문에 API 응답이 너무 느릴 때가 있다. 이럴 때 캐시를 사용하면 응답시간이 많이 줄어든 경험이 있을 것이다. ( 인메모리에 올려서 한 경우도 있지만?... ) 그렇다고 무조건 캐시를 사용하면 될까? 남용하게 되면 서비스의 신뢰성이 떨어지는 경우가 발생할 수도 있다. Cache 도입할때 고려사항 - 1. 정보가 잘 변경되지 않는 경우 + 처리 시간이 긴 경우 이를 고려하지 않고 도입을 한다면 데이터가 맞지 않아 서비스의 신뢰성이 떨이지게 된다 Cache 도입할때 고려사항 - 2. 빈번한 동일 요청 빈번하게 동일한 검색 요청을 하게 된다면 Cache 도입을 고려해볼 수 있다. 디스크에서 읽어오는 것 보다 서버의 메모..
JPA 15장. 고급 주제와 성능 최적화 성능 최적화 1 - 읽기 전용 쿼리의 성능 최적화 Entity가 영속성 컨텍스트에 관리되면 다양한 혜택을 얻을 수 있다. 하지만 dirty check를 위해 snapshot 인스턴스를 보관하므로 더 많은 메모리를 사용하는 단점이 있다. 대량의 데이터를 조회만 할거기 때문에 읽기 전용으로 메모리 사용량을 최적화할 수 있다. 1) 읽기 전용 트랜잭션 사용 - 속도 최적화 @Transactional(readOnly=true) 해당 옵션을 주면 Spring Framework가 Hibernate Session의 Flush 모드를 Manual로 설정하여, 강제로 flush()를 하지 않는 한 flush()가 일어나지 않는다. 트랜잭션이 커밋되어도 플러시되지 않음 flush() 할 때 일어나는 스냅샷 비교와 같은 무..
1장. JPA 소개 나는 개발 시작할 때부터 Spring + JPA를 사용하였기 때문에 JPA 없이 직접 SQL문을 작성하거나, JdbcTemplate을 사용해보지 않았다. JPA가 없던 시절의 고민 데이터베이스 테이블 설계는 그렇게 열심히 하면서 , 왜 객체 모델링은 대충하고 단지 테이블에 맞추는데 급급할까? 테이블을 만들고 객체는 객체스럽게 만들어도 두개 차이를 메우기 위한 SQL 작업이 너무 많아짐 -> 결국, 객체 모델이 데이터 중심의 모델로 퇴화하게 됨... JPA가 주는 행복 CRUD SQL 작성할 필요 없음 조회된 결과를 객체에 자동 매핑 객체답게 개발하다보니 유지보수도 훨씬 좋아짐 SQL을 직접 다루면? 엔티티에 필드 추가되면? -> 모든 쿼리 수정 반복,반복,반복.... SQL에 의존적인 개발 -> 뭔가 잘..
Spring Boot Test 및 심화 커머스 회사에서 개발을 하다보면 테스트 코드의 중요성은 스스로 깨닫게 된다. 그래서 Spring Boot 테스트 기능에 대해 간단히 정리해 보려한다. 테스트 코드는 멋으로 하는거 아니냐? 이렇게 생각하신 분은 아직 테스트 코드를 짤 줄 모르거나 짜지 않아서라 생각한다. 내가 생각하는 테스트 코드의 장점은 코드가 자동으로 깔끔해진다. 테스트 코드를 짜려면 결국 한가지 기능을 가진 클래스를 짤 수 밖에 없다. 리팩토링에 대한 자신감이 생긴다. 다른 개발자들에게는 설명서가 된다. (가장크다고 생각하는 부분) 테스트 코드가 없다면 주문/결제 테스트를 위해서 웹사이트에 들어가 상품검색부터 정보 입력까지 다 한 후에 코드를 테스트해야 한다. 한번만 테스트하면 끝이 나는가?? 수정->테스트->수정->테스트의 무한 반..
Spring을 이용하여 개발할 때 고민, 클린코드 짜기, 코드리뷰 항목 개발자라면 자신과 팀원들을 위해서 깔끔한 코드를 짜야 한다. 나도 항상 잘 짜고 싶고 고민이 많아 해당 블로깅을 통해 정리를 해놓으려고 한다. 1. 최소한의 정성은 들였는가? ( 중복, 단일 책임원칙, 의미를 담은 상수 ) 먼저 기본적으로 살펴볼 목록은 이정도 인 것 같다. 코드에 중복된 부분은 없는가? 코드가 무엇을 하는 것인지 이해가 불편하지 않은가? 코드가 자신이 있어야 할 자리에 있는가? 앞으로 변경이 일어난다면 어떤 것이 있을 수 있고, 그 변화에 쉽게 대응할 수 있게 작성 되었는가? // 읽기 편한 코드를 만들자! private boolean canUpgardeLevel(User user){ Level currentLevel = user.getLevel(); switch(currentLevel..
JPA / ORM 개발시 성능 향상시키기 스프링 개발을 하면서 ORM을 일반적으로 사용한다. 그 이유는 아래와 같다고 생각한다. relational 은 Object-oriented 프로그래밍과 매치가 되지 않음 다양한 RDBMS SQL 사용법 하지만 ORM framework ( Hibernate, EclipseLink )를 사용하면 성능을 신경써야 한다. 프레임워크가 모두 해결해 줄것이라 생각했다가는 나중에 성능 향상을 위해 코드를 전부 수정하여야 한다. 1. 연관관계에서 기본 FetchMode를 사용하라. JPA에서 기본 FetchMode는 One-to-One, Many-to-One : EAGER One-to-Many, Many-to-Many : LAZY 이다. 다 알다시피, LAZY를 사용하면 query가 한번 더 날아가는 대신 지금 필요없..
JPA 8장 - 프록시와 연관관계 정리 객체는 객체 그래프로 연관된 객체들을 탐색한다. 그런데 객체가 데이터베이스에 저장되어 있으므로 연관된 객체를 마음껏 탐색하기 어렵다. JPA 구현체들은 이 문제를 해결하려고 프록시라는 기술을 사용한다. 이를 이용하면 실제 사용되는 시점에 데이터베이스에서 조회할 수 있다. 하지만 자주 사용하는 객체는 조인을 사용해서 함께 조회하는 것이 더 효과적이다. JPA는 즉시 로딩 ( eager )과 지연 로딩 ( lazy ) 를 지원 한다. 프록시 지연 로딩 기능을 사용하려면 실제 엔티티 객체 대신에 데이터베이스 조회를 지연할 수 있는 가짜 객체가 필요한데 이를 프록시 객체라 한다. JPA 표준 명세는 지연로딩의 구현방법을 JPA 구현체에 위임했다. 따라서 지금부터 나오는 내용은 하이버네이트 구현체에 대한 내용이다..
Spring JPA 이슈 모음 1. detached entity passed to persist @Table(name = "good_base") @NoArgsConstructor public class GoodsBase implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(updatable = false, name = "good_idx") private Long goodsId; @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL) @JoinColumn(name = "good_idx", referencedColumnName = "good_idx") private List g..