25%
66,000원
다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결실전! Querydsl
17강 조인 - on절을 듣다가 질문드립니다.
안녕하세요. 스프링입문부터 강의를 듣다가 처음으로 질문드립니다. 17강 조인 - on절을 듣던중 join_on_filtering() Test예제에서 잘 모르겠는 부분이 있어서 질문드립니다. 모든 member를 조회하고 teamA이면 team을 left outer join 으로 조회하는 케이스였는데요 list<Tuple> result 를 loop한 결과 ``` tuple = [Member(id=3, username=member1, age=10), Team(id=1, name=teamA)] tuple = [Member(id=4, username=member2, age=20), Team(id=1, name=teamA)] tuple = [Member(id=5, username=member3, age=30), null] tuple = [Member(id=6, username=member4, age=40), null] ``` 이렇게 나왔습니다. 제가 여기서 3번째 항목(index 2)의 Team이 Null인것을 확인하여 결과를 화면에 찍어보다가 result.get(2).get(member).getTeam() 을 했을때 teamB에 대한 select query 없이 TeamB가 출력되는 결과가 나타났습니다. 1. query 결과상 team_id(FK)는 null 이 나왔는데 result.get(2).get(member).getTeam() 과 result.get(2).get(team) 의 차이가 궁금합니다. 2. teamA에 대해 select 했기 때문에 result.get(2).get(member).getTeam() 가 null 이 나오거나 구문을 수행하면 teamB에 대한 select query를 실행할줄알았는데, LAZY와 상관이 없는것인지, teamB에 대한 select query 없이 teamB에 대한 내용이 출력될수 있는지 궁금합니다. (select query가 없어서 영속성 컨텍스트 1차캐시에서 바로 불러온줄 알았는데 그 전에 teamB에 대한 조회쿼리가 없었습니다) ps1. p6spy query로그를 보았을때 궁금한점이 있습니다. ``` /* select member1, team from Member member1 left join Team team with member1.team = team and team.name = 'teamA'1 */ select member0_.member_id as member_id1_1_0_, team1_.team_id as team_id1_2_1_, member0_.age as age2_1_0_, member0_.team_id as team_id4_1_0_, member0_.username as username3_1_0_, team1_.name as name2_2_1_ from member member0_ left outer join team team1_ on (member0_.team_id=team1_.team_id and team1_.name=NULL); ``` 주석안에 쿼리는 parameter가 잘 나왔는데 밑에 실제 query에는 NULL로 나오고 실제 수행된 결과는 parameter가 잘 적용된 결과가 나옵니다. ㅎㅎ... ps2. 사내에서 주 RDBMS를 Oracle로 사용하고있습니다.(과거 Oracle ERP를 사용하면서 주 RDBMS로 선택했고, 현재 SAP ERP로 전환하였지만 Legacy System의 DB는 95% 이상 Oracle로 운영되고있습니다) 기존 Legacy는 거의 Mybatis로 query mapping을 하고있는데 orm을 처음 적용하여 개발을 진행해보려고 합니다. 현재 dialect로 Oracle10gDialect를 사용하여 실습중인데 실습한 내용을 바탕으로 실 운영환경에서 잘 적용할 수 있을지 걱정이됩니다.
- 미해결실전! Querydsl
alias 질문드립니다 !
안녕하세요. 비전공 개발공부 8개월차 주니어입니다. 먼저 정말 유익한 강의 감사드립니다. 제게 큰 도움이 됐습니다. 다름아니고 질문드릴게 있는데요, 퇴근 후 QueryDSL로 토이프로젝트를 하고있습니다. 일별 방문자 수와, 누적 방문자 수 통계를 구하고 있는데요. 우선 제가 작성한 쿼리입니다. SELECT SUM(R.C) FROM (SELECT COUNT(DISTINCT CLIENT_IP) AS C FROM REQUEST_LOG GROUP BY DATE(REG_DATE) ) AS R; 쿼리 의도입니다. 1. 로깅테이블(REQUEST_LOG)에서 일별로 그룹핑하고, 클라이언트 IP로 중복을 제거한 값을 구합니다. (일별 방문자) 2. 일별 방문자를 모두 더합니다. (누적 방문자) 이걸 QueryDSL로 옮기려니 표현식과 alias를 쓰기가 막막한 느낌이 있습니다. 제가 참고한 문서와 작성한 코드입니다. http://www.querydsl.com/static/querydsl/3.6.3/reference/ko-KR/html_single/#alias @Override @Transactional(readOnly = true) public Long allVisitors() { JPAQueryFactory queryFactory = new JPAQueryFactory(getEntityManager()); return queryFactory .select(requestLog.clientIp.countDistinct()) .from(requestLog) .groupBy(functionDate(requestLog.regDate)) .fetch() .stream() .reduce(0L, Long::sum); } private StringTemplate functionDate(DateTimePath regDate) { return stringTemplate("date({0})", regDate); } 결국 alias를 어떻게 쓸지 잘 알지 못해 우선 서브쿼리를 포기하고 단순 select 문으로 일별 방문자수를 구해온 후 어플리케이션에서 stream으로 일별 방문자수를 모두 더해 누적 방문자수를 구해서 구현했습니다. 근데 그냥 자바코드없이 QueryDSL만을 이용해서 쿼리한방에 끝내고 싶지만 방법을 잘 알지 못해 어떻게 해결해야 할지 계속 고민중입니다. 혹시 실례가 안된다면 간단한 예제코드나 힌트 좀 주실 수 있으실까요? 😥 전체적인 소스코드 주소입니다. https://github.com/shirohoo/Application-SubscribeTechBlogs
- 미해결실전! Querydsl
안녕하세요. 실무에서의 방식에 대해 궁금한 사항이 있습니다.
안녕하세요. 영한님 퀄리티 좋은 강의를 해주셔서 감사합니다. JPA를 이용한 개인프로젝트를 하는 중에 의문사항이 생겨서 질문드립니다. 실무 즉, 현업에서는 신규 기능개발을 할 때 스키마를 설계해야하는 경우라면 DB스키마를 먼저 설계하고 이에 맞게 Entity 도메인을 설계하나요??
- 미해결실전! Querydsl
혹시 JPA에서 table partition 을 관리할 수 있나요?
안녕하세요. 강의를 수강하고 있는 도중에 로그성 테이블에 대해서 table partition을 JPA를 통해 생성하고 관리할 수 있는지 궁금합니다. 인터넷을 찾아보니... EclipseLink 에서 table partition 을 지원한다고 하는데요.. spring data jpa 에서도 제공되는지 궁금합니다.
- 해결됨실전! Querydsl
Querydsl 사용 중 오류
query dsl 사용중에 다음과 같은 오류가 발생했습니다. 오류 1 . DataJpaTest org.hibernate.PersistentObjectException: detached entity passed to persist: 오류 2. JPS incremental annotation processing is disabled. Compilation results on partial recompilation may be inaccurate. Use build process "jps.track.ap.dependencies" VM flag to enable/disable incremental annotation processing environment. Annotation Processer는 체크되어있는 상태입니다. lombok을 최신버전으로 명시해줘도 해결되지 않았습니다. 하나의 dependency를 추가하면 정상 실행되는 이상한 현상(?)이 발생했습니다. 추가한 dependency를 삭제하면 여전히 실행되지 않았구요. (특정 dependency가 아니라 무엇이든 상관없었습니다.) => 질문을 올린 이후에 gradlew clean / build로 해결하였습니다. 저와 같은 현상을 겪는 분들이 많은 것 같아 질문은 삭제하지 않고 남겨두도록 하겠습니다. <gradle 파일> (일부러 h2 부분 주석처리 해놓았습니다.) plugins { id 'org.springframework.boot' version '2.4.4' id 'io.spring.dependency-management' version '1.0.11.RELEASE' id 'java' id "com.ewerk.gradle.plugins.querydsl" version "1.0.10" id "io.franzbecker.gradle-lombok" version "3.0.0"}group = 'ShallWe'version = '0.0.1-SNAPSHOT'sourceCompatibility = '11'configurations { compileOnly { extendsFrom annotationProcessor }}repositories { mavenCentral()}dependencies { implementation 'junit:junit:4.12' compile group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2' compile group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'com.querydsl:querydsl-jpa' compileOnly 'org.projectlombok:lombok' runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'// runtimeOnly 'com.h2database:h2' annotationProcessor 'org.projectlombok:lombok'// testImplementation 'org.springframework.security:spring-security-test' implementation('org.springframework.boot:spring-boot-starter-validation') testImplementation('org.springframework.boot:spring-boot-starter-test') { exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' }}test { useJUnitPlatform()}//querydsl 추가 시작def querydslDir = "$buildDir/generated/querydsl"querydsl { jpa = true querydslSourcesDir = querydslDir}sourceSets { main.java.srcDir querydslDir}configurations { querydsl.extendsFrom compileClasspath}compileQuerydsl { options.annotationProcessorPath = configurations.querydsl} <application.yml> spring: output: ansi: enabled: always datasource: url: jdbc:mariadb://localhost:3306/shallwetest?useUnicode=true&characterEncoding=utf-8 username: username password: password driver-class-name: org.mariadb.jdbc.Driver jpa: hibernate: ddl-auto: update #create , create-drop , update , validate, none properties: hibernate: show_sql: true format_sql: true
- 미해결실전! Querydsl
queryDsl에서는 DATE 함수 지원 하지 않나요?
SELECT * FROM member AS m INNER JOIN history AS h ON (m.id = h.id) WHERE DATE(h.created_at) = DATE_ADD(CURDATE(), INTERVAL -1 DAY) 해당 쿼리문을 만들어야 하는데요... 지금 까지 제가 해본 것 입니다!!!! 함수 () { LocalDate minusDays = LocalDate.now().minusDays(1); DateTemplate<LocalDate> localDateDateTemplate = Expressions.dateTemplate(LocalDate.class, "DATE({0},'%Y-%m-%d')", subQEmrConsultationHistory.createdAt, ConstantImpl.create("%Y-%m-%d")); BooleanBuilder booleanBuilder = new BooleanBuilder(); booleanBuilder.and(localDateDateTemplate.eq(minusDays)); return queryFactory .from(qhistory) .join(qhistory.member) .where(booleanBuilder) } 이렇게 한번 해보았는데 당연히 안되었네요... 이방법이 아닌거 같은데요... 이 경우 어쩔수 없이 Mybatis로 가야하나요....
- 미해결실전! Querydsl
EntityManager Id(pk)값 부여 질문드립니다.
안녕하세요, 강의 잘 보고 있습니다. 질문을 드리고 싶어서요. Member memberA = new Member(); em.persist(memberA); 를 하면, Mysql의 IDENTITY 전략의 경우 영속성 컨텍스트에 memberA를 저장하려면 Id값이 필요합니다. 그래서 DB에 insert 쿼리를 날립니다. 그리고 DB에서 배정받은 pk값을 가져와 그제서야 영속성 컨텍스트에 (배정받은 pk값, memberA)의 형태로 저장을 하는데요. 질문 1. 그럼 영속성 컨텍스트 안에 있는 memberA 의 id필드에 pk값이 삽입되어 있는 건가요? 질문 2. 맨 처음 Member를 생성했던 Member memberA = new Member(); 에 있는 memberA의 id필드도 DB에 insert할 때 할당받은 pk값이 삽입되는 건가요?
- 미해결실전! Querydsl
영속성 컨텍스트 쿼리 질문 드립니다.
안녕하세요, 강의 잘 듣고 있습니다. 질문을 드리고 싶어서요. 영속성 컨텍스트에 엔티티A가 있다고 가정해 볼게요. EntityManager의 em.find()를 통해 엔티티A를 조회하면, EntityManager는 영속성 컨텍스트에 있는 엔티티A를 반환하고, 실제 DB에 select 쿼리는 날리지 않는걸로 알고 있어요. 그런데 queryFactory는 생성자 인자로 EntityManager를 받고 있음에도, 왜 해당 강의 7분 21초에서는 select 쿼리가 나가나요?? queryDSL은 EntityManager 차원의 find 실행이 아니고, JPQL 차원의 쿼리 실행이라, 무조건 쿼리가 나가는 건가요??
- 해결됨실전! Querydsl
동시성 처리가 된건지 모르겠습니다.
@Transactionalpublic boolean enrollCourse(String studentId, Long courseId){ Course findCourse = courseRepository.findById(courseId).get(); if(findCourse.getCurrentNumStudent() == findCourse.getMaxNumStudent()) return false; Student findStudent = studentRepository.findById(studentId).get(); StudentCourse studentCourse = new StudentCourse(); studentCourse.enrollCourse(findStudent, findCourse); findCourse.addCurStudentNum(); studentCourseRepository.save(studentCourse); return true;} service의 메소드 입니다. 위의 동시성 처리 시나리오는 수강신청 최대 인원(findCourse.maxNumStudent)이 50명이고 현재 신청인원(findCourse.currentNumStudnet)이 49명일 때 동시에 여러 학생이 수강신청을 할 경우의 동시성 처리입니다. false를 반환 받으면 controller에서 클라이언트로 신청할 수 없다는 메세지를 전달합니다. JPAQueryFactory는 Repository마다 생성하고 JPAQueryFactory에 초기화하는 EntityManager는 주입받아서 전체 Repository에 공통으로 사용하고 있습니다. @Transactional 에너테이션을 추가했고, JPAQeuryFactory를 사용했으므로 동시성 처리가 되고 있는 건지 궁금합니다. 더 생각 해 본것이 메소드에 synchronized 를 사용하는 것도 괜찮을 까요? 클라이언트의 요청마다 스레드가 생기는 것이니까 가능할 것 같다고 생각합니다. 또, 혼자서 개발할 때 동시성 처리를 테스트 할 수 있는 좋은 방법이 있는지 궁금합니다.
- 해결됨실전! Querydsl
DTO .as 질문
안녕하세요 영한님! 강의 영상 5:36 경에 new QMemberTeamDto 인자의 member.id처럼 필드명이 맞지 않는거를 as로 바꿔주셨는데 @QueryProjection 방법 특성상 생성자로 Dto를 만들어 select하는거라 타입만 맞으면 되지 않나요?? 만약 일부로 as를 사용하신거면 dto 안에 이러한 필드가 있다고 좀 더 명시적으로 나타내기 위한 장치인가요?
- 미해결실전! Querydsl
Dto안에 List<Dto> 조회하기
public class AaaDto { private long id; private List<BbbDto> bbbs = new ArrayList<>(); } AaaDto를 조회하려고 합니다. .select(Projections.fields(AaaDto.class, Aaa.id, Projections.fields(BbbDto.class, ) ) 이런식으로 구현을 해보니 BbbDto 는 List가 될 수 없다는 에러는 반환하더라구요. 이런 경우에 한번에 Dto로 만드는 방법이 있을까요? JPAExpressions으로 감싸서 select fetch를 해보려 하였지만 잘 안되네요,,, 조언을 구해보고자 질문 올려봅니다. 감사합니다.
- 미해결실전! Querydsl
캐멀케이스 질문
안녕하세요! 정말 간단한 질문인데 구글링해도 딱히 나오지 않아서 질문드립니다. 2:00 에 보면 필드명이 username, teamName 하셨는데요 username은 왜 캐멀케이스를 사용하지 않나요??
- 미해결실전! Querydsl
페치 조인과 on 절
안녕하세요! 4:39초 코드에서 질문 있습니다. 코드를 left조인으로 수정, where절 대신 on절 추가로 코드를 바꿔봤습니다. on절로 걸러진 것들을 left join하고 Lazy인 것을 페치 조인으로 땡겨올 것이라 예상했는데 오류가 나더라구요 혹시나 해서 활용편을 다시 봤는데 fetch join 예시에서는 on을 사용하지 않으셨더라구요 fetchjoin은 on절과 사용하지 못하는 건가요? List<Member> findMembers = queryFactory .selectFrom(member) .leftJoin(member.team, team).fetchJoin().on(team.name.eq("teamA")) .fetch();
- 미해결실전! Querydsl
querydsl 의 order by 문에서 cast 와 replace 를 사용하는 방법
김영한님 현재 해당 sql 쿼리를 querydsl 바꿔야하는 상황이고 제품의 가격별로 페이징 및 정렬을 해야하는 상황입니다.문제는 현재 product table 에 있는 데이터가 ₩8,000 이렇게 들어가 있는 상태고 전부 string 입니다. 그런제 저가순/고가순 그리고 페이징 까지 적용해야하는 상황인데sql문까지는 만들 수 있는데, 문제는 querydsl 로 적용하는 부분에서 막혔습니다.이게 sql 문이고 select * from product order by cast(replace(replace(product.price,‘₩’,‘’), ‘,’,‘’) as decimal) asc; orderby 구문에서 replace 와 cast 를 전부 적용해야하는 데, 변환가능한 문제인지 묻고싶습니다 ㅠ 염치불구하고 두서없이 질문드려서 죄송합니다...
- 미해결실전! Querydsl
안녕하세요? 여쭤볼 곳이 없어 질문남깁니다
회사에서 MSSQL을 사용하고 있습니다 기존에 마이바티스를 사용하고 있었고 최근 JPA와 querydsl을 도입했습니다 MSSQL특성 상 SELECT 쿼리에 with(nolock) 힌트를 줘서 써야한다하기에 셀렉트 쿼리에 한하여 @Transactional (isolation = Isolation.READ_UNCOMMITTED) 를 줬습니다 현재 배포시 의문의 락이 걸리고 있는 상황인데, 개발서버에서는 아무 이상이 없고 운영에만 넘어가면 락이걸리네요 아무튼 상황은 이렇구 제 의문은 이겁니다 with(nolock)힌트를 줘서 더티리드를 한다고 한다면 JPA는 어쨋건 읽어오면서 영속성 컨텍스트에 저장을 하게되잖습니까? 그럼 더티리드를 여러군데서 해간다고 한다면 정합되지 않은 해당 정보들이 모두 영속성 컨텍스트에 들어간 상태인데, 그 상황에 어딘가에서 변경감지를 통한 업데이트 쿼리가 발생한다고 한다면 이게 정확히 어떤식으로 동작하는지가 궁금합니다. 현재 발생하고 있는 의문의 락과 연관이 있을까요?
- 해결됨실전! Querydsl
MemberRepositoryImpl
좋은강의 감사드립니다! 처음으로 DB 를 사용함에 있어서 흥미를 가지게 되었네요!! 다름이 아니라 궁금한 점이 생겼는데 스프링 컨테이너가 MemberRepositoryImpl 을 사용하게 되는 것 같은데 컨테이너에 어떻게 해당 클래스가 빈으로 등록되는지 감이 잘 오지 않습니다. ㅠㅠ ****RepositryImpl 이라는 규약을 두고 해당 클래스를 빈으로 등록시켜주는 매커니즘일까요??
- 해결됨실전! Querydsl
재밌게가 아닌 신나게 들었습니다 ㅋㅋ
기존 Spring , JPA 강의가 재밌는 강의라면 Querydsl은 신나는 강의네요. 어? 이것도 가능해? 아니 이것도 된다고?? 여기에 더해서 이런것까지 해줘? 강의 듣는 내내 감탄사만 나왔네요 ㅎㅎ 직접 jpql을 건드릴 때는 상상할 수도 없던 것들이 다 가능하게 되는게 너무 신기합니다. 기존 JPA 강의에서 Querydsl을 엄청 강조하신 이유가 이제야 알겠네요 ㅎㅎㅎ 마지막 강의는 조금 저한테는 어렵긴 했지만 Function<Target, Result> 로 만든 파라미터가 결국에는 람다식을 파라미터로 넣기 위한 자바기능이란것도 이해했구요. (계속 복기하다보면 어느샌가 이해되겠죠 ㅎㅎ) 덕분에 신나게 강의 들었습니다! 감사합니다~~
- 해결됨실전! Querydsl
결과적으로는 바인딩받은 조건으로 검색하려면
그냥 앞전에 우리가 배운 Condition 클래스를 만들어서 그걸로 바인딩 받아서 where 문에 넣으면 되나요? 제 눈에는 그게 더 직관적이더라구요. Querydsl을 복잡한 실무환경에서 사용할때도 클래스로 바인딩받아서 BooleanExpression 메소드 만들어서 쓰면 될까요? 항상 감사합니다~
- 미해결실전! Querydsl
강좌 너무 감사합니다. 강의 자료는 원본으로 받을수 없을까요?
진짜 너무 좋은 강의 감사합니다. 강의 자료를 프린트해서 볼려니 페이지 수가 너무 많아요..ㅠㅠ 빈줄도 많고...ㅠㅠ pdf를 다른(한글,워드등) 파일로 변환하여 수정하여도 쉽지 않더라구요, 강의 자료를 pdf파일이 아닌 수정 가능 파일로 첨부해주실수 없는지요. 사용하신 프로그램이름과 파일 원본과 그리고 pdf를 같이 올려주시면 사용자가 골라서 다운 받으면 좋지 않을까 싶어요~^^
- 미해결실전! Querydsl
QueryDSL 계층형 쿼리
안녕하세요JPA와 QueryDSL을 공부하다가 궁금한 점이 생겨서 질문 드립니다.상품의 카테고리 테이블이 있고 해당 카테고리는 자기자신을 참조하는 형태로 계층 구조를 가지고 있다고 하면 API 응답 구성은 { "category_seq":"1", "parent_id":null, "name":"root", "children":[ { "category_seq":"2", "parent_id":"1", "name":"child_1", "children":[ { "category_seq":"4", "parent_id":"2", "name":"child_1_1", "children":[ ] } ] }, { "category_seq":"3", "parent_id":"1", "name":"child_1", "children":[ ] } ] } 아래와 같은 형태로 구성하고 싶습니다. 그렇게 되면 아래와 같은 entity 가 나오고 public class Category { @Id @GeneratedValue(generator = "uuid2") @Column(columnDefinition = "varchar(36)") @GenericGenerator(name = "uuid2", strategy = "org.hibernate.id.UUIDGenerator") private String categorySeq; @Column private String name; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "parent_seq") private Category parent; @OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST,fetch = FetchType.LAZY) private List<Category> children = new ArrayList<Category>(); } QueryDSL에서는 from(qCategory).join(qCategory.children).fetchJoin() 으로 조회를 할텐데 API의 응답 구성으로 계층화 시키려고 하면 child를 접근하는 부분에서 N+1 문제가 발생합니다. 혹시 이 부분에 대한 해결 방법이 있을까요? 아래는 SQL 문 입니다. select category0_.category_seq as category1_0_0_, children1_.category_seq as category1_0_1_, category0_.name as name5_0_0_, category0_.parent_seq as parent_s6_0_0_, children1_.name as name5_0_1_, children1_.parent_seq as parent_s6_0_1_, children1_.parent_seq as parent_s6_0_0__, children1_.category_seq as category1_0_0__ from t_category category0_ inner join t_category children1_ on category0_.category_seq = children1_.parent_seq ; --------------------- child 부분 ----------------------- select children0_.parent_seq as parent_s6_0_1_, children0_.category_seq as category1_0_1_, children0_.category_seq as category1_0_0_, children0_.name as name5_0_0_, children0_.parent_seq as parent_s6_0_0_ from t_category children0_ where children0_.parent_seq in ('540a0597-1273-4925-84da-e0a0f86f234a', 'kf0a0597-1273-4925-84da-e0a0f86f234a'); ....... 생략 --------------------- child 부분 -----------------------