안녕하세요 영한님 강의 잘 듣고 있습니다!! 일대다 페치조인에서 페이징을 하게되면, 메모리 상에서 페이징을 한다고 이해했습니다. 만약 페치조인 쿼리가 DB로 가면, 뻥튀기된 로우들이 메모리에 올라오게 되고 distinct를 JPA가 하게됩니다. 이 상황에서 만약 페이징이 이루어진다면 뻥튀기된 로우에서 offset만큼 결과를 리턴하게 되다고 이해했습니다. 결론적으로 생각하면 뻥튀기된 로우를 페이징하기 위한 쿼리와 전체를 가져오는 쿼리가 같은 상황에서, 왜 메모리상에서 페이징하는 것이 위험한가요?
안녕하세요 질문을 둘러보았는데 저랑 딱맞는 고민은 없는거 같아서 질문드립니다. 프론트/백서버를 나누지 않고 한 서버로 구현할 경우 JWT를 페이지 이동시 매번 어떻게 헤더로 보내줄까요?? fetch api나 ajax를 통한 api 호출시 헤더 보내는것은 문제없지만 아예 다른 매핑으로 페이지를 이동할 경우 인증이 필요한 페이지에 접근하려면 header에 bearer token이 필요한데 도대체 어떤 방법으로 구현할지 모르겠습니다. 프론트서버를 나눈경우 이게 어려운게 아닌일 같은데 리다이렉션을 헤더요청과 함께하려는 꼴이 되서 안되는거 같네요,.. 그래서 일단은 cookie에 토큰값을 넣어주고 쿠키값에서 찾아오도록하고 있습니다..... 쿠키는 헤더에 자동으로 계속 추가되니깐요.. 그냥 이렇게 해도 상관없을까요 쿠키에 토큰 자체를 넣어버려도 괜찮을지요 프론트와 백이 분리 되지 않고 spring security로 설계한 서비스의 경우 jwt인증을 매 페이지 마다 어떻게 수행할지가 고민입니다. 감사합니다.
1. persistence.xml 2. Member.java package hellojpa ; import javax.persistence.* ; @Entity // JPA 의 관리 대상이 된다 . public class Member { @Id @GeneratedValue @Column (name = "MEMBER_ID" ) private Long id ; @Column (name = "USERNAME" ) private String username ; // // @Column(name = "TEAM_ID") // private Long teamId; @ManyToOne @JoinColumn (name = "TEAM_ID" ) private Team team ; public Long getId () { return id ; } public void setId (Long id) { this . id = id ; } public String getUsername () { return username ; } public void setUsername (String username) { this . username = username ; } public Team getTeam () { return team ; } public void setTeam (Team team) { this . team = team ; } } 3. Team.java package hellojpa ; import javax.persistence.* ; import java.util.ArrayList ; import java.util.List ; @Entity public class Team { @Id @GeneratedValue @Column (name = "TEAM_ID" ) private Long id ; private String name ; // Team 객체에서 Member 클래스를 참조하기 위해 @OneToMany (mappedBy = "team" ) private List<Member> members = new ArrayList<>() ; public Long getId () { return id ; } public void setId (Long id) { this . id = id ; } public String getName () { return name ; } public void setName (String name) { this . name = name ; } public List<Member> getMembers () { return members ; } public void setMembers (List<Member> members) { this . members = members ; } } 4. JpaMain.java package hellojpa ; import javax.persistence.EntityManager ; import javax.persistence.EntityManagerFactory ; import javax.persistence.EntityTransaction ; import javax.persistence.Persistence ; import java.util.List ; public class JpaMain { public static void main (String[] args) { // 엔티티 매니저 팩토리는 하나만 생성해서 애플리케이션 전체에서 공유 EntityManagerFactory emf = Persistence. createEntityManagerFactory ( "hello" ) ; // DB 커넥션을 얻는 일관적인 행위를 할때마다 EntityManager 를 만들어줘야한다 . // 엔티티 매니저는 쓰레드간에 공유 X ( 사용하고 버려야 한다 ) EntityManager em = emf.createEntityManager() ; // // JPA 의 모든 데이터 변경은 트랜잭션 안에서 실행 . EntityTransaction tx = em.getTransaction() ; tx.begin() ; // 트랜젝션 시작 try { // 저장 Team team = new Team() ; team.setName( "TeamAA" ) ; em.persist(team) ; Member member = new Member() ; member.setUsername( "member22" ) ; member.setTeam(team) ; em.persist(member) ; em.flush() ; em.close() ; Member findMember = em.find(Member. class, member.getId()) ; List<Member> members = findMember.getTeam().getMembers() ; for (Member m : members) { System. out .println( "kkk = " + m.getUsername()) ; } tx.commit() ; } catch (Exception ex) { tx.rollback() ; } finally { em.close() ; } emf.close() ; // 웹 애플리케이션에서 WAS 가 종료될 때 emf 종료 => release //code em.close() ; emf.close() ; } } 문제 1. 콘솔창에 kkk = 결과값이 나오지 않습니다. 문제 2. H2 DB에 저장되지 않습니다. em.flush(); em.clear(); 를 지우고 했을 때는 저장이 되지만 마찬가지로 결과값은 나오지 않았습니다. em.flush(); em.clear();를 붙이니 결과값도, DB에 저장도 되지 않았습니다. 원인 파악 부탁드립니다 ㅠㅠ 디버깅 해보았는데도 잘 모르겠어요 ㅠㅠ
안녕하세요 영한님! 다름이아니라 제가 이해한 내용이 맞나 궁금해서 질문드립니다. 시퀀스 전략 중 allocationSize에서 이 값이 50이면 시퀀스를 한 번에 50씩 증가하고 그만큼 메모리에 1~50까지 식별자를 할당하는데 50까지 차면(51일 때) 시퀀스 값을 한 번 더 50 증가시켜 100까지 할당하는 방식이라고 하셨습니다. 처음에 조금 헷갈리거나 이해가 안갔던 부분은 시퀀스 값이 1이면 애플리케이션에서 1~50까지 사용하고 시퀀스 값이 2이면 애플리케이션에서 51~100까지 기본 키를 사용하는 건데, 제가 이를 이해한 것은 네트워크시간에 배우는 TCP의 슬라이딩 윈도우 개념과 비슷하지 않나 해서 이와 유사한 아이디어라고 이해하였는데 이렇게 생각해도 되나요??ㅎㅎ; 시퀀스 값 1마다 기본키 50으로 묶이는건 세그먼트와 바이트번호 관계처럼 묶이는(?) 개념이라 생각이 듭니다. 감사합니다 // 슬라이딩 윈도우
내 업무를 대신 할 파이썬(Python) 웹크롤링 & 자동화 (feat. 주식, 부동산 데이터 / 인스타그램)
주피터 노트북 실행시 질문입니다. 1. jupyter-lab 실행 시 'jupyter-lab'은(는) 내부 또는 외부 명령, 실행할 수 있는 프로그램, 또는 배치 파일이 아닙니다. jupyter -lab usage: jupyter [-h] [--version] [--config-dir] [--data-dir] [--runtime-dir] [--paths] [--json] [--debug] [subcommand] jupyter: error: one of the arguments --version subcommand --config-dir --data-dir --runtime-dir --paths is required 이게 나옵니다. 안되는 이유가 궁금합니다. 2. 부모폴더(user)로 이동할려고 지정된 경로를 찾을 수 없습니다. 라고 나오는데 왜그런건가요? 3. 제가 주피터 노트북을 d드라이브에 설치하여서 cd로 D;juypter_notebook을 이동할려고 해도 다시 사진 처럼 c드라이브로 원상복구 되는데 이것은 왜그런건지 궁금합니다. 4. 탐색창에 주피터 노트북 아이콘을 클릭해서 실행하면 제대로 작동이되는데 프롬프트에서 실행하면 안되는 이유가 궁금합니다.
안녕하세요. 제가 람다랑 optional, 컬렉션 그런부분을 아직 잘몰라서 자바 공부가 더 필요한데요. 이 부분 듣다가 궁금증이 있어서 질문 남기게 됐습니다. - 중점적인 내용은 `findName 메소드를 findById메소드 처럼 구현하면 안되냐`입니다. -> 다른 질문글을 통해 id는 유일한 기본키로 사용되서 중복이 없고, 이름은 중복이 있을 수 있다고 하셨습니다. 제가 코드는 정확히 모르겠지만 영한님의 강의를 들어보며 추측해보면 -> store - 객체 -> , values() - 값들중 -> . stream() - 모두 돌리는데 -> .filter() - 가로안에 있는 조건에 해당하는 값이 걸리면 -> .findAny() -리턴해라 이런 의미의 식 같습니다. 또 filter 안에 있는 람다표현식?은 member를 받아서 받은 멤버 객체의 name이 findByName 메소드 호출시 매개변수로 받은 name과 같은지를 체크한 것 같구요. 여기서 궁금한점이 store의 member를 하나씩 쭉 돌리는데 우리가 매개변수로 넘겨준 name과 같은 member를 모두 optional에 담아서 반환하는건가요? 즉, findById는 중복 없이 Optional에 하나의 Member 객체만 담아서 반환되어 코드를 저렇게 짠 것이고 findByName은 중복이 있을 수 있어, 매개변수로 받은 name과 같은 모든 member 객체를 optional에 담아 반환해주는 코드인건가요?
예제에서는 DB 리소스 설정 이후에도 루트접근이 가능해 보이는데, 저의경우는 접근이 불가능합니다 아래 이미지는 서버 기동 직후, 브라우저를 통해 루트 접근시 차단이 되는 부분에 BreakPoint 를 잡아 캡쳐했습니다. 익명 사용자의 경우에 허용되어야 할 `/` 웹 루트 경로가 Denied 되는 것은 어느 부분이 문제일까요.. DB 연동은 잘 처리가 되었으나 이부분에서 막힙니다. 특별히 설정을 바꾼것이 없는데 DB 연동 처리 이후, 계속 여기서 부터 막힙니다. 어느 부분부터 살펴봐야 해결이 될까요..? 혹시 정상인가요? ( 지난 강의 돌려보다가 문뜩 생각이 듭니다) 혹제 제가 놓친부분에 대해 조언을 구합니다. 읽어주셔서 감사드립니다.
안녕하세여. Jupyter 실행하기 부분에서. 기본위치를 Desktop 으로 하고 Python_class로 기본 위치를 설정 해주셔서 보여주시는데 제 PC같은경우에는 초기 화면에서 DIR를 입력시 Desktop 폴더가 아예 존재하질 않습니다. 이럴경우 어떻게 하면 좋을까요?
목록페이지를 그냥 들어가면 # 이름 이렇게 잘 뜹니다. 하지만 회원등록을 하고 난 후 회원목록에 들어가면 Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateProcessingException: Could not parse as expression: "${member.id" (template: "members/memberList" - line 19, col 15)] with root cau member.id 를 찾을수없다고 나옵니다 ㅠㅠ
안녕하세요 강의 중 잘 안되는게 있어서 질문드립니다. 강의를 따라하는 중 .env에 SECRET_KEY값을 담아서 사용하는데 다음과같은 에러가 발생합니다. C:\Users\deokpro\Desktop\Django\venv\lib\site-packages\environ\environ.py:628: UserWarning: C:\Users\deokpro\Desktop\Django\pragmatic\pragmatic\.env doesn't exist - if you're not configuring your environment separately, create one. warnings.warn( Traceback (most recent call last): File "C:\Users\deokpro\Desktop\Django\venv\lib\site-packages\environ\environ.py", line 273, in get_value value = self.ENVIRON[var] File "C:\Users\deokpro\AppData\Local\Programs\Python\Python39\lib\os.py", line 679, in __getitem__ raise KeyError(key) from None KeyError: 'SECRET_KEY' ........ django.core.exceptions.ImproperlyConfigured: Set the SECRET_KEY environment variable print문으로 env('SECRET_KEY')를 찍어보면 값이 정상적으로 들어오는게 확인되는데 python manage.py runserver만 하면 에러가 발생합니다. 혹시 해당내용 관련해서 조언을 구하고자 질문드립니다.
안녕하세요. 방학기간을 통해 스프링에 대해 공부하고 있는 대학생입니다. 다름이 아니라 스프링 핵심원리 강의에서 역할과 구현을 분리하라고 배웠습니다. 그래서 만약 '회원 저장소'를 만든다고 하면 pubic interface MemberRepository{ void save(Member member); Member findById(Long memberId); } 을 만들고 필요한 구현체를 따로 만들었습니다. 메모리를 이용한다면 public class MemoryMemberRepository implements MemberRepository { private static Map<Long, Member> store = new HashMap<>(); @Override public void save(Member member) { store.put(member.getId(), member); } @Override public Member findById(Long memberId) { return store.get(memberId); } } 이런 식으로 만들고, 만약 JPA를 이용한다면 public class MemberJpaRepository implements MemberRepository { @PersistenceContext private EntityManager em; public void save(Member member) { em.persist(member); } public Member findById(Long id) { Member member = em.find(Member.class, id); return member; } } 이런 식으로 만들어서 사용했습니다. 여기서 스프링데이터JPA를 사용하기 위해선 인터페이스에 JpaRepository를 상속받아야하는데 그러면 기존에 있던 MemberRepository에 상속받아서 사용하면 되나요? 그런데 MemberRepository에서 JpaRepository를 상속받게 되면 기존에 MemberRepository 구현체들이 JpaRepository까지 모두 구현해야하는 문제가 있고, MemberReposity에서 사용하는 메소드 이름과 JpaRepository에서 사용하는 메소드 이름이 같으면 MemberRepository를 주입받아 사용하는 다른 클래스에도 문제가 발생했습니다. 이래저래 글이 길었지만 그래서 어떻게 스프링데이터 JPA를 사용하면서 역할과 구현을 구분할 수 있을까요?
조인/ 단일테이블 / 구현클래스마다 테이블 이 세가지 전략에 대한 소스코드를 교재에서 확인할 수 있는데요 세 전략 모두 Item 클래스를 추상클래스로 선언했음에도 아래와 같은 차이를 보입니다. '조인' / '단일테이블' 의 경우에는 ITEM 테이블이 생성된 반면,[그림7.3, 그림7.4] '구현클래스마다 테이블'에서는 ITEM 테이블이 생성되지 않는 것으로 이해되고 있습니다.[그림 7.5] 왜 이런 차이를 발생시키는 것인지 궁금합니다. 별개로, 강의에서는 '조인'/'단일테이블' 설명하실 때 Item클래스를 추상클래스로 선언하지 않으셔서 이 부분도 혼동을 주고있습니다.
주문취소쪽 테스트하다가 궁금한점 있어 질문드립니다. 취소할 주문ID를 조회하고 Order order = orderRepository.findOne(orderId); order.cancel(); 로 주문취소하기 전에 orderItems에 값이 넣어져 있는지 모르겠습니다. Order와 OrderItem은 @OneToMany로 기본이 LAZY 로딩이라 orderItems을 직접 호출하기 전까지는 데이터를 조회하지 않는거로 알고 있는데 어떻게 orderItems에 값이 채워져서 취소가 되는지요?... for (OrderItem orderItem : orderItems ) { orderItem.cancel() ; } 저 for문 시점에 데이터를 조회하면 이해하겠는데 디버깅해보면 order를 조회할때 이미 값이 다 채워져 있습니다...
강의에서 영한님께서는 커맨드와 쿼리를 구분하는 것을 선호하신다고 하셨습니다. 그래서 알아보니 이런걸 CQRS라고 하던데 회원 정보를 update시 update command 메소드 실행 후 보통같으면 update메소드 자체의 반환값으로 member객체나 member id를 받는데, 이것을 명령과 질의를 구분해 memberService.update() 후 memberService.findOne을 실행하면 결과적으로 쿼리문을 한번 더 실행을 하게 되잖아요? update 메소드 내에서도 findOne이라는 메소드를 호출하니깐요. 이렇게 명령과 질의를 분리하였지만 그 대가로 쿼리문을 한번 더 호출하게 된 셈인데 쿼리문을 한번 더 호출해서 명령과 질의를 구분하는 것이 많이 효율적인 패턴인가요?