Spring
[Spring 3.1] 템플릿과 콜백
[Spring 3.1] 템플릿과 콜백
2023.04.19템플릿은 코드 중에서 변하지 않는 부분을 변하는 부분으로부터 독립시켜 효과적으로 활용하는 기법을 말한다. 스프링 프레임워크에 적용된 템플릿 기법을 살펴보고 Data Access Object에 적용해보자. DAO는 데이터베이스와 연결하는 부분이 필수적으로 포함된다. 데이터베이스와의 연결은 Connection Pool을 통해 이루어지고, 커넥션을 모두 사용했다면 반환해 다시 풀에 넣어 줘야 한다. try { // connect.. } catch (Exception e) { } finally { // close.. } 어떤 상황에서도 가져온 리소스를 반환할 수 있도록 try-catch-finally 구문을 사용한다. 제대로 작성한다면 커넥션 풀이 꽉 차는 현상은 막을 수 있지만.. DAO를 작성할 때 마다 t..
[Spring 3.1] 스프링과 테스트
[Spring 3.1] 스프링과 테스트
2023.04.16웹 애플리케이션을 제작하고 제대로 동작하는지 테스트하려면 어떻게 해야 할까? 특정 기능을 테스트하기 위해 해당 테스트와 연계된 서비스, 컨트롤러, 뷰, 웹 서버 환경을 모두 구축해야 테스트 할 수 있다. 여기서 테스트가 실패한다면? 테스트하려는 특정 기능에서 오류가 발생했는지, 아니면 다른 연계된 기능에서 오류가 발생했는지 확인하기 전에 알 수 없다. 즉, 웹 서버를 띄워서 테스트하는 경우 디버깅 비용이 매우 많이 발생한다. 테스트하려는 대상이 명확한 경우 그 대상에만 집중해서 테스트를 진행하는 편이 합리적이다. 이렇게 작은 단위의 코드에 대해 진행하는 테스트를 단위 테스트라고 부른다. 자바는 JUnit 테스트 프레임워크를 제공해 개발자가 단위 테스트를 쉽게 진행할 수 있도록 도와준다. (개발의 전반적인..
[Spring 3.1] 관심사의 분리와 스프링
[Spring 3.1] 관심사의 분리와 스프링
2023.04.13추후 유지 보수를 고려했을 때 관심사 (도메인) 를 작업 단위로 소스코드를 분리해서 작성하는 편이 합리적이다. 이런 측면에서 추상 클래스와 인터페이스는 매우 중요하다. 확장성 있는 애플리케이션을 구현하기 위해 디자인패턴 중 템플릿 메서드 패턴을 사용한다. abstract class Car { public void doorOpen() { } public abstract void drive() { } } class ACar extends Car { public void drive() {...} } 슈퍼 클래스에 기본적인 로직을 만들어 놓고, 일부 기능을 추상 메서드로 만든다. 이후 서브 클래스에서 해당 메서드를 필요에 따라 구현해서 사용하도록 하는 패턴이다. 변화의 성격이 다른 것들을 분리해서 서로 영향을 ..
[QueryDSL] 활용 (Spring Data JPA + QueryDSL)
[QueryDSL] 활용 (Spring Data JPA + QueryDSL)
2023.01.11웬만한 기능은 Spring Data JPA가 제공해주고, 동적 쿼리 등 복잡한 구현이 필요할 때 QueryDSL 기술을 사용한다. 따로 Repository를 하나 만들어서 기능을 구현하자. MemberRepositoryCustom을 인터페이스로 만들고 구현할 기능을 선언한 후 MemerRepositoryImpl에 기능을 구현한다. public class MemberRepositoryImpl implements MemberRepositoryCustom { private final JPAQueryFactory queryFactory; public MemberRepositoryImpl(EntityManager em) { this.queryFactory = new JPAQueryFactory(em); } @Ov..
[QueryDSL] 활용 (JPA + QueryDSL)
[QueryDSL] 활용 (JPA + QueryDSL)
2023.01.11실제로 애플리케이션을 설계할 때는 Repository 계층을 만들고 Repository를 통해 데이터베이스와 상호작용한다. 먼저 Spring Data JPA 기술 없이 순수 JPA와 QueryDSL 만 사용해서 Repository를 설계해보자. @Repository public class MemberJpaRepository { private final EntityManager em; private final JPAQueryFactory queryFactory; public MemberJpaRepository(EntityManager em) { this.em = em; this.queryFactory = new JPAQueryFactory(em); } public void save(Member member..
[QueryDSL] 중급 문법
[QueryDSL] 중급 문법
2023.01.101. 프로젝션 프로젝션 대상이 하나인 경우 대상 타입을 명확하게 지정할 수 있다. 제네릭스를 String으로 설정하고 값을 받아온다. (객체도 가능) 프로젝션 대상이 둘 이상인 경우 QueryDSL이 제공하는 Tuple 자료구조나 DTO를 따로 정의해서 반환값을 가져올 수 있다. 왼쪽은 Tuple을 사용하는 예시이다. 일단은 Tuple도 QueryDSL에 종속적인 타입이기 때문에, 바깥 계층으로 반환될 때를 생각하면 DTO를 사용하는 편이 합리적이다. (Repository 내부에서만 사용하는 경우는 괜찮다) JPA를 사용할 때 DTO를 따로 정의해서 반환값을 가져오려면 new 명령어를 사용해 DTO의 생성자를 호출하는 방식을 사용해야 한다. QueryDSL 기술을 사용하면 좀 더 간단하게 처리할 수 있다..
[QueryDSL] 기본 문법
[QueryDSL] 기본 문법
2023.01.09QueryDSL은 Query Domain Specific Language의 약자로 간단하게 JPQL을 만들어주는 역할을 한다고 생각하면 된다. @Test public void startJPQL() { String qlString = "select m from Member m " + "where m.username = :username"; Member findMember = em.createQuery(qlString, Member.class) .setParameter("username", "member1") .getSingleResult(); assertThat(findMember.getUsername()).isEqualTo("member1"); } @Test public void startQuerydsl..
[Spring Data JPA] 내부 동작 원리
[Spring Data JPA] 내부 동작 원리
2023.01.03Spring Data JPA 기술이 제공하는 공통 인터페이스의 구현체를 살펴보자. SimpleJpaRepository 클래스가 공통 인터페이스를 구현한다. @Repository 애너테이션이 붙어있다. 따라서 Spring의 Component Scan의 대상이 되고, 특정 계층에서 예외가 터진 경우 Spring이 다루기 쉬운 예외로 변환한다. 덕분에 구현 기술을 바꾸더라도 기존 기술에 영향을 주지 않는다. @Transaction 애너테이션도 붙어있다. 모든 데이터의 변경은 Transaction 내부에서 진행되어야 한다. Spring Data JPA는 기본으로 제공하는 기능에 모두 @Transaction 애너테이션을 붙이기 때문에 개발자가 좀 더 편하게 개발할 수 있다. 단순히 조회만 하는 작업에서 @Tran..
[Spring Data JPA] 사용자 정의 리포지토리와 확장 기능
[Spring Data JPA] 사용자 정의 리포지토리와 확장 기능
2023.01.03Spring Data JPA 가 제공하는 기능을 사용하면 개발이 생산성이 증가하지만, 상황에 따라 특정 기능은 Spring Data JPA가 제공하는 방법 대신 다른 방법을 사용해야 하는 경우가 생긴다. (JPA를 직접 사용한다던가, MyBatis를 사용한다던가...) 이럴 때는 어떻게 해야 할까? Spring Data JPA는 이런 경우 Custom Repository를 사용할 수 있도록 한다. 사용자가 직접 인터페이스를 만들고, 필요한 기능을 원하는 방법으로 구현한 후 Spring Data JPA와 합치는 방식으로 문제를 해결한다. MemberRepositoryCustom에 구현하려는 기능을 선언하고, MemberRepositoryImpl에서 기능을 구현한다. (둘 다 인터페이스이다) 이후 JpaRe..
[Spring Data JPA] 벌크 연산과 EntityGraph
[Spring Data JPA] 벌크 연산과 EntityGraph
2023.01.02JPA를 공부할 때 배웠듯, 한 번에 여러 데이터들을 한 번에 수정하는 경우 벌크 연산을 사용한다. Spring Data JPA에서 벌크성 수정 쿼리를 작성할 때는 @Modifying 애너테이션이 붙는다. 벌크 연산은 영속성 컨텍스트를 무시하고 바로 데이터베이스에 쿼리를 보내기 때문에 영속성 컨텍스트로 관리되는 엔티티의 상태와 데이터베이스에 저장된 데이터가 서로 일치하지 않는 경우가 발생할 수 있다. 따라서 벌크 연산을 수행한 이후 flush와 clear함수를 실행해 영속성 컨텍스를 초기화 하는 방법을 사용하자. @Modifying(clearAutomatically = true) 로 설정하면 해당 애너테이션이 붙은 메서드가 실행된 후 영속성 컨텍스트가 자동으로 초기화된다. Spring Data JPA에서..
[Spring Data JPA] 쿼리 메서드와 페이징
[Spring Data JPA] 쿼리 메서드와 페이징
2023.01.02Spring Data JPA 기술을 사용해 회원의 이름과 나이를 기준으로 조회하는 기능을 구현한다고 생각해보자. 공통으로 제공하는 메서드가 아니기 때문에 별도로 처리해 줘야 하는데, 이 때 쿼리 메서드 기능을 사용하면 매우 편하게 처리할 수 있다. 쿼리 메서드를 사용하면 이전처럼 JPQL을 하나하나 작성하지 않아도 된다. 쿼리 메서드는 메서드의 이름을 바탕으로 JPQL을 만들어주는 기술이다. 위와 같이 메서드의 이름을 적절하게 작성하고 매개변수를 설정하면 직관적으로 어떤 JPQL이 만들어지는지 유추할 수 있따. 이 때 아무 이름이나 사용하면 안 되고, 관례가 있다. 이름에 사용되는 관례는 (https://docs.spring.io/spring-data/jpa/docs/current/reference/ht..
[Spring Data JPA] 공통 인터페이스
[Spring Data JPA] 공통 인터페이스
2023.01.02기존에는 JPA를 사용해 원하는 기능을 하나하나 작성해 줘야 했지만, Spring Data JPA기술을 사용하면 개발을 훨씬 편하게 할 수 있다. 단순하게 인터페이스를 만들고 JpaRepository 클래스를 상속받는것만으로도 Spring Data JPA의 기능을 사용할 수 있다. 그런데 구현체가 아닌 인터페이스를 사용하는데 어떻게 기능을 사용할 수 있을까? Spring Data JPA는 인터페이스를 통해 구현체를 만들고 주입해준다. 애플리케이션이 로딩될 때 개발자가 만들어놓은 인터페이스를 보고 구현 클래스를 만드는 방식으로 작동한다. (프록시) 개발자는 JpaRepository 클래스의 제네릭스만 적당히 설정해주면 Spring Data JPA의 기능을 사용할 수 있고, 인터페이스에는 @Repositor..