본문 바로가기

Back-End/JPA

(17)
JPA 에러 - Deadlock found when trying to get lock; try restarting transaction Deadlock found when trying to get lock; try restarting transaction Deadlock이 발생하게 된 코드 및 상황 @Transactional(isolation = Isolation.SERIALIZABLE) override fun save(userNo: Int, productId: Int): Order { return repository.findByProductId(productId)?.let { println("[${Thread.currentThread().id}] - $productId count is increased - ${it.count}") it.count += 1 return repository.save(it) } ?: createOrder(u..
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에 의존적인 개발 -> 뭔가 잘..
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..
Spring JPA 다대다 설정 및 성능 주의 ( Many To Many ) 소개 복잡한 비즈니스 요구 사항이 들어오게 되면 다대다 관계로 모델링을 진행하여야 한다. 이때 어떻게 해야하는지 주의해야 할 점에 대해 정리해보고 싶어 해당 글을 쓰게 되었다. Many to Many 학생이 좋아하는 수업을 정의할 때 다대다 관계가 필요해진다. 여러명의 학생이 수업을 좋아할수도 있고, 한 학생이 여러 수업을 좋아할 수도 있다. 이걸 RDB로 표현을 하면 아래와 같은 다이어그램이다. JPA 코드로 표현을 하면 아래와 같다. @Entity class Student { @Id Long id; @ManyToMany @JoinTable( name = "course_like", joinColumns = @JoinColumn(name = "student_id"), inverseJoinColumns =..
Spring JPA의 사실과 오해 - NHN FORWARD 1. 연관관계 매핑 Entity 매핑 / 연관관계 매핑 정규화를 통해서 최소한의 데이터를 받아오도록 한다. 그렇기 때문에 FK를 이용하여 객체 참조와 매핑항여 사용한다. 그때 다중성, 방향성을 고려하여 설정을 한다. ( OneToOne, OneToMany, ManyToOne, ManyToMany ) 대개의 경우 단방향 매핑이면 충분하다. ( 양방향 매핑은 복잡하고 객체에서 양쪽 방향을 모두 관리해줘야 함 ) 영속성 전이 다대일인 경우 단방향으로도 영속성 전이가 잘됨 일대다 단방향 연관관계 매핑인 경우(Cascade.ALL) : @Transactional public void creeateMember(){ memberRepository.save(member); // MemberDetail 생성및 세팅 } ..
16장. 트랜잭션과 락, 2차 캐시 및 내 생각 현업에서 주문, 결제 등등 민감한 데이터를 수정하는 경우 항상 트랜잭션과 관련된 내용이 나온다. 락은 자원을 선점하도록 설계하지 말고 보통 기본으로 사용하다가 문제가 발생하면 그때 대응하는 식으로 개발했다. ( 대용량 트래픽의 회사에서 근무하시거나 제가 잘못된 개발 방법이라면 언제든 댓글 달아주세요 ) 트랜잭션과 격리수준 원자성(Atomicity) : 트랜잭션 내에서 실행된 작업들은 마치 하나의 작업처럼 모두 성공하거나 모두 실패해야 한다 일관성(Consistency) : 데이터베이스에서 정한 무결성 제약조건을 항상 만족해야 한다 격리성(Isolation) : 동시에 실행되는 트랜잭션들이 서로에게 영향을 미치지 않도록 격리한다. 예를 들어, 동시에 데이터를 수정하지 못하도록 한다. 하지만, 격리성은 동시..
14장. JPA 컬렉션과 부가기능 하이버네이트는 엔티티를 영속 상태로 만들 때 컬렉션 필드를 hibernate 에서 준비한 collection으로 감싸서 사용한다. 예제를 살펴보자 Team team = new Team(); // before persist Sysout(team.getMembers().getClass()); //java.util.ArrayLists em.persist(team); // after persist Sysout(team.getMembers().getClass()); // org.hibernate.collection.internal.PersistentBag 결과를 보면 영속 상태로 변경된 후에 hibernate가 제공하는 PersistentBag로 변경되었다. 원본 컬렉션을 감싸고 있어서 레퍼 컬렉션이라고 부르기도..