안녕하세요! 강의 너무 잘 보고 있습니다. 스프링 혼자 공부해보려다가 넘 어려워서 안하게 됬는데, 흥미롭게 진행해주시는 강의듣고 조금씩 알아가는 것 같아 스스로도 기쁘고 감사합니다.ㅎㅎ 질문1 [스프링 빈과 의존관계]-[자바 코드로 직접 스프링 빈 등록 하기] 강의 7분 26초 에서 setter 주입 방식의 단점으로 ... 어플리케이션 로딩 시점에 한번 세팅되고 나면 이 멤버변수는 바꿀 일이 없는데 public으로 노출되게 된다는 점이 단점이라고 설명해주셨습니다. 그런데 6분 0초 필드 주입방식을 설명해주실 때 단점으로... 스프링이 시작될 때, 초기에만 설정되고 개발자가 동적으로 바꿀 수 없어서 추천하지 않는 방식이라고 설명해주셨는데요! 질문은! 어플리케이션 로딩 시점에 한번만 세팅되면 되는 거면, 필드 주입방식에서 초기만 설정되고 나중에 바꿀 수 없다는 점이 왜 단점이 되는 건지 이해가 잘 안됩니다! 한번 더 단점을 정리해주실 수 있을까요? 질문2 [스프링 빈과 의존관계]-[자바 코드로 직접 스프링 빈 등록 하기] 강의 2분 40초 에서 memberRepository() 메소드 반환형을 왜 MemoryMemberRepository 타입으로 하지 않고, 인터페이스 타입으로 하신 건지 궁금합니다. + 11분 25초 부분까지 강의를 들으니 알겠네요. ^^상황에 따라 다른 데이터베이스를 연결하는 내용의 리포지토리를 연결할 때, 서비스나 컨트롤러 코드를 변경하지 않고, 아래 파일에서 new 하는 객체만 원하는 리포지토리로 바꿔주면 되니까 그런거군요! package hello.hellospring.service ; import hello.hellospring.repository.MemberRepository ; import hello.hellospring.repository.MemoryMemberRepository ; import org.springframework.context.annotation.Bean ; import org.springframework.context.annotation.Configuration ; @Configuration public class SpringConfig { // @Bean : spring bean 을 등록할 거라는 의미 @Bean public MemberService memberService (){ return new MemberService ( memberRepository ()); } @Bean public MemberRepository memberRepository (){ return new MemoryMemberRepository (); } } 질문3 : 컴포넌트스캔방시과 직접자바설정방식 차이 잘 이해한건지 확인부탁드립니다. 컴포넌트 스캔방식 : 스프링은 @Controller, @Service, @Repository 어노테이션이 붙은 것들을 빈으로 등록해 관리한다. @Autowired로 각 빈들을 연결해준다. 직접자바설정 방식 : @Configuration과 @bean으로 스프링에 빈을 등록한다. @Autowired로 각 빈들을 연결해준다. 그런데, 이 강의에서 직접 자바 config를 만들때, @Service, @Repository, @Autowired는 지웠는데, @Controller 은 지우지 않았습니다. 이유가 무엇인가요?
저는 기존에 spring과 mybatis를 사용하다 강의를 듣게되어서 service와 mapper의 역할이 딱 나뉘어진 코드에 익숙했는데 엔티티에 로직이 들어가니 조금 당황스럽네요 ㅎㅎㅎ... 각설하고 다른 질문들을 보았지만 명쾌하게 이해되지는 않아서 강의 내용과 제가 생각한 내용들로 이해해봤는데 맞는지 확신이 안서서 질문드려요 1. 회원 파트와 주문파트의 엔티티 구성방식이 다른 것(생성메서드,비즈니스 로직등의 유무) 은 회원은 기능구현시 타 엔티티와 상호작용하는 부분이 없어 간단한 구현이라는 판단아래에 별 로직이 없고 주문파트는 상호작용하는 부분(주문 취소시 수량 복구, 주문이라는 행위시 연관되는 엔티티정보들) 이 있기에 많은 로직이 있다는 걸로 받아들이면 될까요? 2. 주문 취소의 경우 서비스 부분에 들어가는게 맞다고 생각했는데 엔티티에 구현하셔서 질문들을 찾아보니 취소가 되기 위해선 주문엔티티의 배달상태의 정보가 바뀌고,수량 복구가 되어야하고 해당하는 정보들이 가장 가까운 Order와 OrderItem엔티티에서 로직을 수행한다는 말씀이시고 이게 객체지향 스럽다? 라고 이해하면 될까요?
안녕하세요? 강사님. 항상 좋은 강의 잘 보고 있습니다. 이번강의를 보면서 에러가 발생하였습니다. Member member = new Member ( "member1" , 10 ); memberRepository . save ( member ); Member findMember = memberRepository . findById ( member . getId ()). get (); assertThat ( findMember ). isEqualTo ( member ); assertThat부분에서 <"Member(id=1, username=member1, age=10) (Member@1b444b5)"> to be equal to: <"Member(id=1, username=member1, age=10) (Member@5a1a20ae)"> but was not. Expected :Member(id=1, username=member1, age=10) Actual :Member(id=1, username=member1, age=10) 이러한 에러가 발생했습니다. 알고보니 @Transaction 어노테이션을 선언을 안해서 그랬습니다. member와 findMember의 메모리 주소가 달라서 에러가 발생한것 같은데 메모리가 주소가 왜 다른지 잘 이해가 안됩니다. meber객체를 save 하면서 영속성 컨텍스트에 담기고 findMember는 영속성컨텍스트에 담겨있는 member인것이 아아니라 새로 select문을 날려서 디비에서 조회한 값이더라구요( @Transactional이 없을 때 로그를 통해서 확인하였습니다) @Transactional을 선언 하고 save 후 em.flush(); em.clear();를 해준것과 같은 현상이 나더라구요. @Transactional이 롤백외에도 어떠한 기능이 있길래 이러한 현상이 나타나는지 알고 싶습니다. 감사합니다.
선생님 약간 논외질문이긴한데 ㅜㅜ count나 알려주셨던 기본 함수들의 반환형을 어떻게 확인해야할지 모르겠습니다. count함수를 이용해서 뽑아보려고하는데 결국 구글검색으로 long 타입으로 뽑으면 알 수 있다고 해서 알았습니다. 혹시 count나 다른 기본함수들에 대해서 제가 반환형을 알 수 있는 방법이 있을까요? 이런식으로 계속 object 타입으로 호출했습니다... String query= "select count(m) from Member m" ; Query emQuery = em.createQuery(query) ; List resultList = emQuery.getResultList() ; for (Object o : resultList) { System. out .println( "object= " + o) ; }
안녕하세요 백기선님! static변수에 관한 질문이 있습니다 static 변수는 컴파일 시점에 메모리에 안착되어 프로그램이 종료될때 까지 살아있다. 그러므로 static 변수가 점유하고 있는 메모리는 가비지컬렉터에 의해 회수되지 않는다. 로 알고 있습니다. https://openjdk.java.net/jeps/122 아래는 해당링크의 일부 내용을 발췌한 것입니다. Class metadata, interned Strings and class static variables will be moved from the permanent generation to either the Java heap or native memory. The code for the permanent generation in the Hotspot JVM will be removed. Application startup and footprint will not regress more than 1% as measured by a yet-to-be-chosen set of benchmarks. 1. java8 부터는 static 변수/함수를 남발한다는 이유만으로 메모리 부족 문제가 생길 가능성이 희박해 진걸가요? 'static 변수를 남발해도 시스템에 크게 지장이없다?' 2. heap 영역으로 옮겼다면 GC의 관리영역으로 들어와서 mark & swap 인 가능해 진 건가요? 개발자 꿈나무입니다 ! 답변의 수준이 낮더라도 이해 부탁드리겠습니다 ㅠㅠ!
JPA 기본편 강의와 같이 듣고 있습니다. 좋은 강의 항상 감사드립니다. (질문 도중 제가 잘못 이해 하고 있는 부분이 있다면 말씀주시기 바랍니다.) 다름 아니라 EntityManager는 요청이 들어올 때 생성되어 사용됬다가 해당 요청이 마무리 되면 삭제된다고 이해 하고 있습니다. 근데 @Repository 를 DI를 통해 생성할 때 @RequiredArgsConstructor 를 통해 EntityManager도 생성해줍니다. 그럼 이 EntityManager 인스턴스는 @RequiredArgsConstructor 위 어노테이션으로 인해 필요할 때 마다 그 때 그 때 생성된다고 볼 수 있을까요? 아니면 싱글톤 객체 안에 필드임으로 그 때 그 때 새로운 값을 할당 받는건가요? 감사합니다, 좋은 하루 되세요~
안녕하세요 강사님, 수강 중 궁금증이 생겨 질문을 남깁니다. 지금까지 설명해주신 연관관계 주인이 왜 존재해야 하는지, 또 어떤 식으로 주인을 설정해야 하는지는 모두 이해했습니다. 설명하신 내용 중에 아래와 같은 내용이 있었는데요. "연관관계 주인이 아닌 관계로는 읽기 기능만 사용이 가능하다. 그 외의 모든 관리는 관계의 주인이 처리한다." 이와 관련하여 팀에 새로운 멤버를 추가하고 싶을 때 team.getMembers().add(member)를 하면 DB에 반영되지 않고, member.setTeam(team)을 해야만 제대로 반영되는 부분까지 이해했습니다. 그런데, member.setTeam(team)으로 멤버가 팀을 가지도록 하고, 트랜잭션 커밋까지 완료해 해당 내용이 DB에 정상적으로 반영이 되었다면.. 그 이후에 따로 team.getMembers().add(member)를 하지 않아도 Team이 가지고있는 List<Member> members에서 방금 추가한 member를 조회할 수 있어야 하는 것이 맞지 않나요? 이를 확인하기 위해 아래와 같은 코드로 실습을 진행하였습니다. try { Team team = new Team() ; team.setName( "TeamA" ) ; em.persist(team) ; Member member = new Member() ; member.setName( "MemberA" ) ; member.setTeam(team) ; em.persist(member) ; tx.commit() ; Team findTeam = em.find(Team. class, member.getTeam().getId()) ; List<Member> members = findTeam.getMembers() ; for (Member m : members) { System. out .println( "Name : " + m.getName()) ; } } catch (Exception e) { tx.rollback() ; } finally { em.close() ; } team을 생성하고 member를 생성하여 member에 team을 할당해줬습니다. em.persist를 통해 해당 객체들을 영속상태로 만들었고 tx.commit으로 flush처리까지 해주었습니다. 하지만 Name : MemberA는 출력되지 않습니다. 물론 DB에는 정상적으로 저장되었더라도 메모리에는 저장되지 않았기 때문에 조회가 안 된다고 말씀하시기는 했지만.. 이 코드의 경우에는 Team과 Member가 정상적으로 DB에 적용된 후에 em.find()를 통해 새롭게 받아온 Team으로 조회한 것인데.. 왜 제대로 조회되지 않는 것인지 모르겠습니다. ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ 추가 질문 하나만 더 드리겠습니다. 관계의 주인이 아닌 List<Member> members는 읽기 전용으로만 사용하기 때문에 members.add(member)를 아무리 해도 DB에 영향을 끼치지는 않겠지만.. 쓰기 권한이 없는 녀석에게 쓰기 메서드가(list.add()) 존재하는 것 자체만으로 어떠한 문제가 야기될 수도 있지는 않을지 궁금합니다. 이 부분에 대해서도 함께 답변해주시면 감사하겠습니다.
안녕하세요? 강사님. 항상 강의 잘듣고 있습니다. 다름이 아니라, 이전에 알려주신 내용에서 밑에 처럼 dto로 조회 할때는 new 오퍼레이션을 사용하셨는데, @Query ( "select new study.datajpa.repository.MemberDto(m.id, m.username, t.name) " + "from Member m join m.team t" ) List<MemberDto> findMemberDto () ; 왜 밑(네이티브 쿼리)에서는 dto 를 조회 할때 new 오퍼레이션을 사용을 안하셨나요..? @Query (value = "SELECT m.member_id as id, m.username, t.name as teamName " + "FROM member m left join team t" , countQuery = "SELECT count(*) from member" , nativeQuery = true ) Page<MemberProjection> findByNativeProjection (Pageable pageable) ; 항상 좋은 강의와 답변 감사드립니다!!^^
선생님 준영속상태의 초기화를 하실때(37분 20초에서 ) Member refMember = em.getReference(Member.class, member1.getId()); 를 해주셨는데 getReference도 find와 같이 문장이 실행되는 순간 영속성컨텍스트에프록시 객체를 올린다음에 초기화시 컨텍스트에서 엔티티를 뒤지고 없으면 db로 가서 끌고온다음에 또 영속성컨텍스트에 올려서 확인을 하는게 맞는지요? 이게맞다면 member1은 em.flush와 em.clear를 통해 영속성컨텍스트에는 존재하지 않으며 db에는 올라가있고 -> getReference코드를 실행시켜서 일단 초기화되지 않는 프록시 객체를 만들었고요 -> detach를 통해서 refmember를 준영속 상태를 만들어주었습니다. 영속성컨텍스트에는 제가 생각할땐 아무것도 없는 상태인데 detach가 왜가능한건가요? 프록시객체가 초기화되어서 엔티티를 만들어낸 것도 아니고 초기화되기전 프록시객체 자체도 영속성컨텍스트에 올라가있는건가요? em.persist(refMember)을 써준것도아니고 ... 프록시객체도 엔티티라고 치고 올린다음에 그안에 참조값을 실제 엔티티생성과 동시에 채워주는건가요? 그리고 두번째로 refmember 자체가 초기화되기전에 만약 team테이블과 연관이 있으면 refmember을 초기화하는순간 member와 team까지 다불러오는건가요? 이건 fetch 속성과 관련이 없는건가요? 이쯤오니 너무 헷갈립니다ㅜㅜ 제 질문을 이해하셨을지 모르겠습니다... 지저분한글 읽어주셔서 감사합니다 선생님 항상 감사합니다.
안녕하세요. 강사님 QueryDSL 재미있게 배웠습니다. 정렬기준을 아래와 같이 받았을 때 pageable 파라미터를 이용해서 QueryDSL에 적용하는 방법에 대해서 고민입니다. 정렬기준 입력 형태: URI?sort=field1,asc&sort=field2,desc org.springframework. data .domain.Sort 방법1. pageable 값을 얻어와 직접 queryDSL에 OrderSpecifier로 지정 if (pageable != null) { query.offset(pageable.getOffset()); query.limit(pageable.getPageSize()); for (Sort.Order o : pageable.getSort()) { PathBuilder<Object> orderByExpression = new PathBuilder<Object>(Object.class, "object"); query.orderBy(new OrderSpecifier(o.isAscending() ? com.mysema.query.types.Order.ASC : com.mysema.query.types.Order.DESC, orderByExpression.get(o.getProperty()))); } } 방법2. applyPagination() 함수로 매핑 getQuerydsl().applyPagination(pageable, jPQLQuery); 결과적으로 방법2가 더 깔끔해 보이는데 원본 엔티티와 DTO객체가 달라서 org.hibernate.hql.internal.ast.QuerySyntaxException이 발생하는 이슈가 있습니다. 현재까지 결론은 방법1을 사용해야할 것으로 보이는데 더 좋은 방법을 아시는지 문의드립니다. 감사합니다.
PDF 파일에서 IntelliJ Gradle 대신에 자바 직접 실행 항목에 적힌 설명처럼 IntelliJ IDEA 변경하고 프로그램 실행시에 /src/main 하위에 generated 폴더가 자동으로 생기는데 왜 생기는건가요?? 안 생기게 못하나요?? 환경 스프링 부트 2.4.2 인텔리제이 얼티메이트 2020.3.1
안녕하세요? 아직까지는 예제에서 데이터를 직접 리턴해주는 방식으로 하고있는데요, 여기서 로이 필딩이 말하는 Restful의 조건을 만족하려면 Self-Descriptive Messages와 HATEOAS를 만족해야 한다고 하는데 이 조건을들 만족하려면 결국 HttpEntity를 사용하여야 하는걸까요? RestTemplate로 작성된 코드를 보고 영한님의 HTTP 강의도 듣고나니 머릿속에서 퍼즐이 맞춰지는 느낌은 드는데 이게 맞는거다 라는 확신은 없어서 제가 제대로 이해하면서 진행하고 있는건지 궁금하여 질문드립니다. 그리고 강의 만족도가 매우 높습니다 ^^ 항상 감사하게 수강하고있습니다. 이대로 QueryDSL까지 열심히 달려서 실무에서 빨리 적용해보고 싶네요 ㅎㅎㅎ
7분 즘에 MemberRepository 클래스르 만들고 @PersistenceContext 어노테이션을 private EntityManager em; 에 붙였는데 원래 정석대로라면 팩토리를 만들고 그걸로 엔티티매니저를 반환받는거였는데 이 어노테이션으로 그 과정을 스킵한다고 봐도 되나요? 팩토리 만들 때 마다 비용이 많이 소모된다고 알고있는데 이 어노테이션도 똑같이 팩토리를 한번만 만들고 그 팩토리로 엔티티매니저를 반환하나요? 그렇다면 이 과정을 알고 있다는 전제 하에 그냥 간단하게 @Autowired 같은 거라고 보면 될까요 ㅎㅎ...
아무리 devtools 를 적용시켜봐도 리컴파일을 하고 새로고침을 해도 페이지 변하지 않길래 구글님에게 수소문 해본 결과 https://lejewk.github.io/springboot-devtool/ 이거대로 해보니 되네요. 혹시나 devtools 동작 안하시는 분들 참고하시라고 공유차원에서 올려봤습니다~
private void close (Connection conn) throws SQLException{ DataSourceUtils.releaseConnection(conn , dataSource ) ; } 2.4.2 버전을 사용하고 있습니다. JdbcMemberRepository 클래스에서 DataSourceUtils에 관한 import가 되질 않아 진행이 안되는데요. Alt + Enter를 눌러도 추천하는 내용에는 import 내용이 없습니다. 어떻게 해결해야 하나요?
영한 스승님 안녕하세요! 본 강의에서 작성하신 querydsl 코드에서요. 궁금한 점이 있습니다! fetchJoin 메서드 호출 없이 join 메서드만 호출할 경우' 주문 엔티티'가 가지고 있는 '멤버 엔티티'를 가져오기 위해 추가적인 쿼리가 호출되지 않을까요? 불필요하게 select 쿼리 내 join 절이 붙어서 나가는 것이 아닌가 궁금합니다.