묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨실전! Querydsl
querydsl Projection 성능 문제
안녕하세요 Querydsl Projection 을 활용해 DTO에 담는경우 성능 관련 질문이 있습니다. Querydsl에서 Projections.constructor를 활용해서 query를 작성하는경우 fetchJoin이 되지 않더라구요.일대 다 관계에서 fetchJoin을 하지 않게되면 n+1 이슈가 발생할거 같은데Projections을 활용하는 환경에서 성능개선은 어떻게 해야할까요?
-
해결됨실전! Querydsl
Querydsl random select 쿼리
https://www.inflearn.com/questions/284950/querydsl-random-select%EA%B4%80%EB%A0%A82년정도 전에 Querydsl에서 ramdom select는 지원하지 않는다고 하셨는데 지금은 찾아보니 Expressions.numberTemplate()을 통해 SQL Function을 사용할 수 있다고 하는데 권장하는 사용법인지, 올바른 random select 방법인지 궁금합니다.추가로 같은 결과를 반환하는 random select, distinct, limit, 프로젝션을 한번에 수행하는 2개의 방법인데 2개의 차이는 다음과 같고 어느것을 추천하시는지 궁금합니다.case1의 방법이 limit를 가져오기에 불필요한 count쿼리를 추가로 날리지 않지만 실행 시간이 더욱 큽니다.case1 - Querydsl 사용테스트 실행시간 : 78mscount 쿼리를 추가로 생성하지 않음public List<QuizWordDto> findMyWordRandomForQuiz() { return queryFactory .select(Projections.constructor(QuizWordDto.class, myWord.name, myWord.morpheme, myWord.mean)) .distinct() .from(myWord) .orderBy(Expressions.numberTemplate(Double.class, "RAND()").asc()) .limit(40) .fetch(); } case2 - 페이징을 이용하여 Limit 가져오기테스트 실행시간 : 22mscount 쿼리를 추가로 생성@Query(value = "SELECT DISTINCT new com.ll.kotudy.word.service.dto.QuizWordDto(mw.name, mw.morpheme, mw.mean) " + "FROM MyWord mw " + "ORDER BY FUNCTION('RAND')", nativeQuery = false) Page<QuizWordDto> findDistinctRandomQuizWords(Pageable pageable);테스트 코드@BeforeEach void init() { for (int i = 0; i < 50; i++) { myWordRepository.save(new MyWord("동물" + i, "명사", "사람을 제외한 길짐승, 날짐승, 물짐승 따위를 통틀어 이르는 말." + i)); } } @Test void findMyWordForQuiz() { long startTime = System.currentTimeMillis(); PageRequest pageRequest = PageRequest.of(0, 40); Page<QuizWordDto> distinctRandomQuizWords = myWordRepository.findDistinctRandomQuizWords(pageRequest); long endTime = System.currentTimeMillis(); System.out.println(String.format("코드 실행 시간: %20dms", endTime - startTime)); } @Test void findMyWordForQuiz_querydsl() { long startTime = System.currentTimeMillis(); List<QuizWordDto> myWordRandomForQuiz = myWordRepository.findMyWordRandomForQuiz(); long endTime = System.currentTimeMillis(); System.out.println(String.format("코드 실행 시간: %20dms", endTime - startTime)); }
-
해결됨자바 ORM 표준 JPA 프로그래밍 - 기본편
JPQL 문법 RollBack
JPQL 작성 시, 전체 조회하면 이상이 없는데 특정 칼럼을 지정하면 RollBack에러가 발생합니다. 어떤 문제인지 알고 싶습니다..
-
미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
JPQL 로 작성한 문법 테스트 코드로 작성해 볼 수 있을까요?
안녕하세요. JPQL 로 쿼리를 작성하고 실제 데이터가 들어가는지 보려고 합니다. 우선, main 함수에서 직접 넣는거는 되는 것을 확인했습니다. 그리고 제가 해보고 싶었던거는 테스트 코드로 작성해보는 것이였습니다. 그런데 Bean을 못찾는다는 에러가 발생했습니다. 구글링도 해보고 빈 등록을 다양하게 해보면서 접근법을 다르게도 해봤는데 해결이 안되네요 ㅠㅠ 혹시 제 코드를 보시고 어디에 문제가 있는지 알 수 있을까요? 제가 작성한 코드입니다. [ JPQLRepository ] @Transactional @Repository public class JPQLMemberRepository implements MemberRepository{ @PersistenceContext private final EntityManager em; @Autowired public JPQLMemberRepository(EntityManager em) { this.em = em; } public EntityTransaction getTx() { return em.getTransaction(); } public Member save(Member member) { em.persist(member); return member; } public void emClose() { em.close(); } @Override public Optional<Member> findByid(Long id) { return Optional.empty(); } @Override public Optional<Member> findByname(String name) { List<Member> result = em.createQuery( "SELECT m FROM Member m WHERE m.name = :name", Member.class ).setParameter("name", name).getResultList(); System.out.println("--------------------------------"); for (Member i : result) { System.out.println("member:" + i); } System.out.println("--------------------------------"); return result.stream().findAny(); } } [ SpringConfig ] @Configuration public class SpringConfig { @Bean public EntityManagerFactory getEnf() { EntityManagerFactory emf = Persistence.createEntityManagerFactory("5xik"); return emf; } @Bean public EntityManager getEm() { return getEnf().createEntityManager(); } @Bean public MemberRepository memberRepository() { return new JPQLMemberRepository(getEm()); } } [ TestCode ] @SpringBootTest @Transactional class JPQLMemberRepositoryTest { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class); MemberRepository repository = ac.getBean("memberRepository",JPQLMemberRepository.class); EntityTransaction tx = repository.getTx(); @Test @Commit void insertData() { tx.begin(); try{ Member member = new Member(); member.setName("sungjun"); member.setPhonenumber("010"); repository.save(member); Optional<Member> result = repository.findByname(member.getName()); Assertions.assertThat(result).isEqualTo(member); tx.commit(); } catch (Exception e){ tx.rollback(); } finally { //repository.emClose(); } //ac.close(); } } 그리고 아직 close를 하는 부분은 구현을 안해놔서주석처리를 해놨습니다 !감사합니다.
-
미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
JPQL 조회 테스트가 올바르게 작성되었나요?
CompStdRepository.java /** * ID로 조회 */public CompStd findOne(Long id) { return em.find(CompStd.class, id);}/** * API ID로 조회 */public CompStd findOneByApiId(String apiId) { String query = "select c From CompStd c where c.apiId = :apiId"; return em.createQuery(query, CompStd.class) .setParameter("apiId", apiId) .getSingleResult();} CompStdService.java /** * ID로 조회 */public CompStd findOne(Long id) { return compStdRepository.findOne(id);}/** * API ID로 조회 */public CompStd findOneByApiId(String apiId) { return compStdRepository.findOneByApiId(apiId);} CompStdServiceTest.java @Testvoid API_ID로_조회() { //given Long createdId = compStdService.insert(getCompStd()); CompStd insertedCompStd = compStdRepository.findOne(createdId); //when CompStd findCompStd = compStdRepository.findOneByApiId(insertedCompStd.getApiId()); //then assertEquals(insertedCompStd, findCompStd);} 1. 다음과 같이 테스트를 작성하였는데 이게 JPQL 조회 기능을 테스트하는 코드로서 올바르게 작성된 건지 궁금합니다. 2. 테스트에서 em.find()로 조회한 객체와 JPQL을 통하여 조회한 객체가 같은 이유는 em.find()로 조회하여 영속성 컨텍스트에 저장된 객체를 JPQL로 조회할 때 객체의 기본 키로 확인하여 같은 객체를 가져오기 때문이라고 보면 될까요?
-
미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
jpql 관련 질문입니다!
안녕하세요 강사님! 강의 잘 듣고 있습니다! JPQL(or Querydsl)과 관련된 질문이 있습니다 FROM절 서브쿼리는 지원하지 않는다고 말씀하셨는데 그 말씀은 아래외 같은 쿼리는 JPQL로 표현이 불가능하다는 말씀이신가요? 불가능하다면 아래와 같은 통계성 서브쿼리가 들어간 쿼리를 어떻게 해결해야 가장 효율적으로 해결할 수 있는건지 궁금합니다!(Querydsl을 사용해서 해결하고 싶습니다) 아래 쿼리는 거래 내역 테이블에서 거래된 아이템별로 그룹핑한 데이터에서 아이템별 최소 가격을 먼저 뽑아내고, 이렇게 만들어낸 인라인 뷰를 아이템 테이블, 브랜드 테이블과 조인하는 쿼리입니다 SELECT i.*, br.*, b.immediately_purchase_price FROM item i INNER JOIN brand br ON br.brand_id = i.brand_id LEFT JOIN ( SELECT item_id, MIN(price) AS immediately_purchase_price FROM bid GROUP BY item_id ) b ON i.item_id = b.item_id ORDER BY release_date DESC LIMIT 16
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
8:30 ~8:36 IDENTITY 질문이있습니다.
13:30~13:36 select m from member m 여기서 select m 저 m자체가 where Member m 의 m호칭 똑같은건가요? 만약 select c from member c 이런식으로도 쓰일수 있는건가요?
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
안녕하세요! 동적쿼리에 대한 질문이 있습니다.
현재 2년차가 되가고 있는 주니어개발자입니다 ( _ _) 아직 경험이 많이 없어 현재 쿼리를 처리하는 퍼시스턴트 프레임워크를 mybaits 정도 밖에 써보지 못 했습니다 선생님께서 말씀하신 것처럼 쿼리를 JPQL로 작성해서 처리할 수 있다고 하셨는데... 아래는 제가 mybatis로 api 처리하고 있는 쿼리입니다. 이런 다소 지저분하고 복잡한 쿼리도 실무에서는 JPQL로 처리를 하나요??? SELECT /* windowClosingPosData */ b.paymentType ,MAX(b.gdName) as gdName ,b.payMethod ,SUM(b.personCnt) as personCnt /* 수량 */ ,SUM(b.price) as price /* 금액 */ ,SUM(b.discountCount) as discountCnt /* 할인매수 */ ,SUM(b.discountAmount) as discount /* 할인금액 */FROM ( SELECT a.paymentType ,a.gdName ,a.payMethod ,( CASE WHEN a.paymentType = 'PAY' THEN a.ticketCount WHEN a.paymentType = 'CANCEL' THEN a.refundCount ELSE 0 END ) as personCnt /* 수량 */ ,( CASE WHEN a.paymentType = 'PAY' THEN a.ticketAmount WHEN a.paymentType = 'CANCEL' THEN a.refundAmount ELSE 0 END ) as price /* 금액 */ ,a.discountCount /* 할인 수량 */ ,a.discountAmount /* 할인 금액 */ FROM ( SELECT 'PAY' as paymentType ,gd.gd_name as gdName ,pm.pm_pay_method as payMethod ,rd.init_rs_ticket_cnt as ticketCount /* 발권매수 */ ,(rd.init_rs_ticket_cnt * rd_price) as ticketAmount /* 발권금액 */ ,0 as refundCount /* 환불매수 */ ,0 as refundAmount /* 환불금액 */ ,( CASE WHEN ifnull(rd.dc_unit_price,0) > 0 THEN rd.init_rs_ticket_cnt ELSE 0 END ) as discountCount /* 할인매수 */ ,(rd.init_rs_ticket_cnt * rd.dc_unit_price) as discountAmount FROM t_reserve_detail rd INNER JOIN t_reserve rs ON rd.rs_seq = rs.rs_seq INNER JOIN t_goods gd ON rs.gd_seq = gd.gd_seq INNER JOIN t_payment pm ON rs.rs_seq = pm.rs_seq AND pm.pm_payment_type = 'PAY' WHERE EXISTS ( SELECT trdp.rs_seq FROM t_reserve_detail_person trdp WHERE trdp.tkt_date = DATE_FORMAT(#{searchDate}, '%Y%m%d') AND trdp.idkey = #{idkey} AND trdp.tkt_win_cd = #{winCd} AND trdp.rs_seq = rs.rs_seq ) AND (rs.gd_package_yn = 'Y' OR (rs.rs_package_yn = 'N' AND rs.gd_package_yn = 'N')) AND rs.insert_idkey = #{memberSeq} UNION ALL SELECT 'CANCEL' as paymentType ,gd.gd_name as gdName ,pm.pm_pay_method as payMethod ,0 as ticketCount /* 발권매수 */ ,0 as ticketAmount /* 발권금액 */ ,rd.cancel_ticket_cnt as refundCount /* 환불매수 */ ,(rd.cancel_ticket_cnt * rd_price) as refundAmount /* 환불금액 */ ,0 as discountCount /* 할인매수 */ ,0 as discountAmount FROM t_reserve_detail rd INNER JOIN t_reserve rs ON rd.rs_seq = rs.rs_seq INNER JOIN t_goods gd ON rs.gd_seq = gd.gd_seq INNER JOIN t_payment pm ON rs.rs_seq = pm.rs_seq AND pm.pm_payment_type = 'PAY' WHERE EXISTS ( SELECT trdp.rs_seq FROM t_reserve_detail_person trdp WHERE trdp.tkt_date = DATE_FORMAT(#{searchDate}, '%Y%m%d') AND trdp.idkey = #{idkey} AND trdp.cancel_win_cd = #{winCd} AND trdp.cancel_member_seq = #{memberSeq} AND trdp.rs_seq = rs.rs_seq ) AND (rs.gd_package_yn = 'Y' OR (rs.rs_package_yn = 'N' AND rs.gd_package_yn = 'N')) AND rs.rs_status = 'D' ) a) bGROUP BY b.paymentType ,b.payMethodORDER BY b.payMethod, b.paymentType DESC JPQL 강의도 들을 계획이지만 이렇게 복잡한 부분을 java단에서 처리한다는게 상상이 되지 않아서 질문드려봅니다 ㅠㅠ