입문자를 위한 Spring Boot with Kotlin - 나만의 포트폴리오 사이트 만들기
안녕하세요. 이젠 기본적인 spring 기능은 이 강의로 많이 알게 되었습니다. 감사합니다. 빨리 강좌 하나 더 내주세요.... 코틀린 & spring 강좌가 너무 없어서 강의 찾아 다니느것도 일이네요 ... ==================================== Docker로 프로젝트 빌드 하기 . 강좌중에 만약 프로그램 수정하면 아래 처럼 하면 되나요? step 1) Gradle에서 jar 파일을 다시 만든다. ... 참고 ) 빌드중에 에러가 없어야함... test 코드에서도 에러가 없어야함 step2) docker-compose.yml 파일 새로고침 한다. step3) Dockerfile을 재 실행한다. step4) 도커가 잘 올라갔는지 확인한다. 프로그램 수정후엔 위 4개의 절차대로 진행하면 되나요?? 이걸로 회사의 개인 서버를 가지고 있는곳에 도커 깔고 동작 하면 서버의 기능으로 완벽할꺼 같은데 .... 그리고 구글 클라우드에도 프로그램 수정하면 도커에서 push up hub 를 누르고 docker-compose.yml 누르면 되나요?? 버전 수정 안해줘도 되나요? 추가 질문) 이건 뭐 제가 잘 모르고 좀 시간을 두고 확인해봐야 하는거라서 질문드리기 어렵지만 그래도 아시면 답변 부탁 드려용 ^^))) 테스트 코드 작성중 아래처럼 DSL로 작성하는 경우를 봤는데 꽤나 직관적이고 편리하게 되어 있더라구요... 아래 같은 테스트 코드 많이 사용하나요?? 비동기 방식에서만 사용하나요?? 테스트 코드 작성하는 방법이 꽤나 많아서 이걸 다 익혀야하는 생기네요 ㅠ.ㅠ 감사합니다. 다음 강의 꼭 내주세요. ^^
안녕하세요! 정말 오랜만에 질문 올립니다. 다름이 아니라 아래와 같이 Parent, Child 가 있고 이 둘을 양방향으로 맺었을때 @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Entity public class Parent { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; @OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST) private final Set<Child> children = new HashSet<>(); public Parent(String name) { this.name = name; } public void addChild(Child... childs) { for (Child c : childs) { c.addParent(this); children.add(c); } } } @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Entity public class Child { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "parent_id", nullable = false) private Parent parent; public Child(String name) { this.name = name; } public void addParent(Parent parent) { this.parent = parent; } } 아래와 같이 테스트코드를 짜면 @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @DataJpaTest(showSql = false) class ParentRepositoryTest { @Autowired ParentRepository parentRepository; @Autowired ChildRepository childRepository; @Rollback(false) @Test @DisplayName("delete, deleteAll, deleteAllInBatch 를 비교한다.") public void differenceBetweenDeleteAllAndDeleteAllInBatch2() { Parent parent1 = new Parent("부모 1"); Child child1 = new Child("자식 1"); Child child2 = new Child("자식 2"); Child child3 = new Child("자식 3"); parent1.addChild(child1, child2, child3); parentRepository.save(parent1); Parent parent = parentRepository.findAllWithChildren("부모 1").get(); parent.getChildren().remove(child1); childRepository.delete(child1); } } parent.getChildren().remove(child1); 의 존재 여부에 따라 delete 쿼리가 나갈지 말지 결정되더라구요. 이거에 대해서 고민을 해봤습니다. 제가 내린 결론은 "하나의 tx 에서 Parent 가 속한 Child 들 중 하나를 childRepository.delete(Child) 혹은 deleteAll() 을 통해 지우려할때, Parent 의 Child 의 컬렉션에서 지울 Child 를 먼저 remove 하여 부모 자식간의 연결관계를 끊어주는 작업이 선행되어야 한다. 그 이유는 삭제할 Child 를 repository 에서 지우기만 하면 Parent 에 남아있는 컬렉션에는 지워진 데이터가 카컬렉션에 남아있어 로직에 문제가 발생할 수 있기 때문이다. 그래서 Parent 에서 지울 Child 를 먼저 remove 를 사용하지 않으면 delete 쿼리가 나가지 않는 것이고, 먼저 remove 를 하면 delete 쿼리가 나가는 것이다" 라고 결정지었습니다. 아무래도 JPA 에서 최고 권위자인 김영한강사님의 조언이 필요합니다. 감사합니다. (고아객체 제거인 orphanRemoval 은 일부러 사용하지 않았습니다. 순수 delete 에서만 그 원리를 알고싶습니다. 항상 무지성으로 querydsl 혹은 in 절로 지우기만해서 근본을 까먹은거같네요 ㅠㅠ)
[질문 내용] h2 db랑 연결이 되지 않는 것 같은데 어제 gradle에서 TRUE 설정을 뺐을 때는 작동이 잘 됐는데 오늘 다시 작동시켜보려 하니 작동이 안됩니다.. MemberRepositoryTest 에서 run을 돌렸을 때 다음과 같은 오류가 발생합니다. 오류는 사진과 같고 zip파일 드라이브에 첨부하겠습니다. https://drive.google.com/file/d/126dOVMwaCPYOSqD4f7XOC0BkCUqtONAK/view 그리고 제가 노트북을 2대를 사용해서 깃으로 관리하고 있는데 그건 큰 관계 없겠죠..? 답변 기다리겠습니다. 감사합니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 안녕하세요 김영한 강사님 항상 강의 잘 보고 있습니다. 다름이 아니라, 연관 관계를 맺고 있는 엔티티들 사이에서 (fetch=FetchType.LAZY,cascade = CascadeType.ALL)에 대해 질문 있습니다. 예를 들어, public class Site { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name="site_id") private Long id; @Column(name="site_name") private String siteName; @Column(name="site_url") private String siteUrl; @ManyToOne(fetch=FetchType.LAZY,cascade = CascadeType.ALL) @JoinColumn(name="directory_id") private Directory directory; public class Directory { @Id@GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name="directory_id") private Long id; @Column(name="directory_name") private String directoryName; @OneToMany(mappedBy="directory", cascade = CascadeType.ALL,orphanRemoval = true) private List<Site> sites = new ArrayList<>(); 에서 directory와 site가 1:N 연관 관계를 맺고 있습니다. 예를 들어, 클라이언트로부터 directory를 조회하는 요청이 온다면 다음과 같이 수행된다고 이해를 하고 있습니다. db에 접근해서 directory를 조회함. 해당 directory entity를 영속성 컨텍스트에 저장함. 이때, fetch=FetchType.LAZY를 사용하고 있기 때문에, 쿼리문을 날릴 때, site를 조회하는 쿼리문을 날리는게 아니라 directory만 조회하는 쿼리문을 날림 그리고 directory 필드에 있는 site는 기본 생성자를 통해 프록시 객체로 생성되어 저장됨. 근데, 여기서 헷갈리는게 그렇다면 "cascade = CascadeType.ALL"는 언제 어떻게 사용되는 것인지 잘 모르겠습니다. 제가 "cascade = CascadeType.ALL"에 대해서 이해하기로는 부모 엔티티와 자식 엔티티를 라이프 싸이클을 동일하게 가져가기 위해서 부모 엔티티가 영속화될 때 자식 엔티티도 같이 영속화 된다. 라는 정도로 이해하고 있습니다. 근데, 여기서 헷갈리는 부분이 directory를 조회하고, directory의 필드로 있는 site는 fetch=FetchType.LAZY로 설정했기 때문에 프록시 객체로 생성됩니다. 그렇다면 이때 site는 directory와 관련된 실제 데이터가 저장되어 있는 객체가 아니라 빈 껍데기같은 객체가 되는게 아닌가요?? 그러면 directory랑 site가 "cascade = CascadeType.ALL로 설정해서 부모 엔티티와 자식 엔티티를 라이프 싸이클을 동일하게 가져간다"라는게 틀린게 되는게 아닌가요?? fetch=FetchType.LAZY,cascade = CascadeType.ALL이 2개를 같이 사용했을 때, 엔티티를 생성,조회 그리고 삭제 하는등의 동작을 수행할 때, 어떻게 동작되는지 연관성과 차이점을 잘 모르겠습니다 .. 매번 훌륭한 강의 감사합니다
[질문 템플릿] 1. 강의 내용과 관련된 질문인가요? 예 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예 3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예 [질문 내용] em.flush() 와 em.clear() 를 하지 않은 영속 상태에서 1차 캐시로부터 가져온 값인 members 에 대해 질문이 있습니다. 아래 코드 중 주석으로 '궁금한 부분'이라 표시한 것 처럼 출력하고자 할 때, 제 예상으로는 1차 캐시에서 members 도 무사히 가져왔으니(확인 완료) 가져온 값을 출력만 하면 될 것 같았습니다. 그러나 이후 실행 결과 출력 되지 않았습니다. 이유를 알려주시면 감사할 것 같습니다! <코드> package hellojpa; import jakarta.persistence.*; import java.util.List; public class JpaMain { public static void main(String[] args) { // 문제 없이 돌아가는 지 확인 EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); // 쿼리를 한 번 날리고 종료되는 일관적인 단위를 할 때마다, 이 EntityManager 를 꼭 생성해야 한다. EntityManager em = emf.createEntityManager(); // JPA 에서 데이터를 변경하는 모든 작업은 꼭 Transaction 안에서 작업을 해야 한다. EntityTransaction tx = em.getTransaction(); tx.begin(); // 트랜잭션 시작 // 실제 code를 작성한다. try { // 팀 등록 Team team = new Team(); team.setName("TeamA"); em.persist(team); // 회원 등록 Member member = new Member(); member.setUsername("userA"); member.setTeam(team); em.persist(member); // JPA 저장 Member findMember = em.find(Member.class, member.getId()); Team findTeam = findMember.getTeam(); System.out.println("findTeam = " + findTeam.getName()); List<Member> members = findMember.getTeam().getMembers(); System.out.println("==============="); // 궁금한 부분!!! // em.clear()~ 등을 하지 않은 영속 상태라고 가정할 때(1차 캐시에서 값을 가져옴) // team 을 통해 members 목록도 불러올 수 있는데, 왜 아래의 iterator 는 작동하지 않을까? for (Member m : members) { System.out.println("통과"); System.out.println("member1 = " + m.getUsername()); } System.out.println("==============="); tx.commit(); // 커밋 } catch (Exception e) { tx.rollback(); } finally { em.close(); } emf.close(); } } <실행 결과>
강의 열심히 들으며 실습하고 있습니다! 헥사고날 아키텍처를 학습하며 적용해 보니 다양한 어려움이 생기더라구요 ㅠㅠ 혹시 entity 내의 from과 to 메서드조차 분리하고자 할 때 궁금한 점이 생겼습니다. Entity 내의 from과 to 메서드로 domain ↔ entity를 변환하는 것을 Converter 클래스를 통해 관심사를 분리하는 것이 괜찮은지? 만일 분리한다면, Converter interface의 위치는 domain 하위 port package일지, infrastructure 하위 port를 만들어 사용할지? (Impl 구현체는 따로 패키지를 생성할 예정입니다) 강의 열심히 듣고 보내주신 책도 잘 받아 열심히 공부하고 있습니다 ㅎㅎ 책에 껴주신 Thankyou.java 파일 잘 받았습니다! 감사합니다
안녕하세요. 회사에서 기술 스택을 코틀린+스프링으로 변경하는데 Querydsl도 같이 사용하려고 학습하고 있습니다. 자료를 찾아보던 중 Querydsl의 유지보수 문제로 Querydsl 대신 다른 쿼리 빌더를 사용한다는 글을 보게 됐습니다. https://spoqa.github.io/2024/05/03/transfer-jdsl.html kapt 이슈 이외에도 Querydsl의 유지보수가 진행되지 않는건 맞아보이는데 Querydsl을 실무에서 도입하는데 문제가 없을지 고민이 많이 되고 있습니다. 실무에서 Querydsl을 도입하는데 문제가 없을지 많은 분들의 의견이 궁금합니다!
[질문 내용] h2 db랑 연결이 되지 않는 것 같은데 어제 gradle에서 TRUE 설정을 뺐을 때는 작동이 잘 됐는데 오늘 다시 작동시켜보려 하니 작동이 안됩니다.. 오류는 10000자가 넘어가서 사진으로 첨부합니다.. zip파일 드라이브에 첨부하겠습니다. https://drive.google.com/file/d/126dOVMwaCPYOSqD4f7XOC0BkCUqtONAK/view
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 5분 18 초에서 필드에서 컬렉션을 초기화해주는 이유가 add할때 nulpointexception을 안뜨게 하기 위해서라고 말씀하셨습니다. 근데 엔티티의 객체를 만들 때, 컬렉션을 생성하고 초기화해서 사용하지 않고 필드에서 초기화해서 사용하는 명확한 이유가 잘 이해가 안되는데 왜 그런건가요??
연결된 서비스 중 307 응답을 주는 서비스가 있습니다. 이 때, 이 응답에 포함된 로케이션으로 자동으로 재요청하도록 설정할 수가 있을까요? Zuul 을 사용할 경우, 동일 요청에 대해 정상적으로 리다이렉트되어 최종적으로 200 이 응답되는데, SCG의 Flux 를 사용하니, 리다이렉트가 되지 않습니다. 찾아보니, webClient 에 구성할 수 있다고 하는데요, SCG에서 구성된 빈을 사용하지 않는 것 같기도 합니다. WebClient.builder() .clientConnector(new ReactorClientHttpConnector( HttpClient.create().followRedirect(true) )) 게이트웨이가 307 Redirect 를 자동으로 재요청하도록 설정할 수 있을까요? 감사합니다.
안녕하세요. 수업 잘 듣고 있습니다. 굉장히 흥미롭게 수업을 듣던 도중 궁금한 것이 이것저것 생겨서 질문드립니다. 수업에서 좀 벗어난 이야기일 수도 있는데 찾아보니 잘 찾을 수가 없어서 질문 드립니다.(혹시 답변하기 힘드시면 안하셔도 괜찮습니다.) 구조를 보니 API gateway는 서비스 ID만 알고있고, 해당 서비스의 실제 ip 주소와 포트 번호를 알기위해서는 Eureka에게 request를 요청해야하는 것 같습니다. 그렇다면 API gateway는 사용자 요청이 들어 올 때마다 매번 Eureka에게 물어보는 방식인가요? 이렇게 되면 통신 오버헤드가 상당이 클 것 같다는 생각이 들어서 질문드립니다. Eureka와 서비스들 간에는 지속적으로 heartbeat message나 서비스 정보 등을 교환하기위해 통신하는 것 같습니다. 혹시 이런 통신은 전부 HTTP 프로토콜을 통해서 이루어지는 것인가요? 혹은 다른 프로토콜을 사용하여 정보를 주고 받나요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 여기에 질문 내용을 남겨주세요. em.createQuery("select m from Member m", Member.class); 이 쿼리를 실행할 때 제가 생각했을때는 1차 캐시에 있는 멤버 객체들을 불러오면 되니까 플러시가 필요없다고 생각했는데 강의에서는 1차 캐시가 아니라 데이터베이스에서 바로 조회를 한다는 식으로 설명하는 듯했는데 어떤게 맞는건가요?
아직 완강은 하지 않았지만 궁금한 점이 생겨 질문드립니다 강의에서 단일모듈 다중 프로젝트로 진행을 하시는데, 이렇게 되면 CI/CD 관리는 어떻게 하는 지 궁금합니다 서비스 마다 Github Repository를 하나씩 만드는 건가요? 단일 프로젝트 멀티모듈은 권장하지 않으시나요? 현업에서는 주로 어떤 방법을 사용하는지 궁금합니다
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 여기에 질문 내용을 남겨주세요. Hibernate: drop table if exists member Hibernate: create table member ( id bigint not null auto_increment, username varchar(255), primary key (id) ) engine=InnoDB Hibernate: insert into member (username) values (?) insert시에 id 값이 보이지 않는 이유가 무엇일까요 ㅠㅠ 파라미터는 id, username 2개가 나와야 하는데 1개만 나와서 질문 드립니다. spring.jpa.properties.hibernate.show_sql=true spring.jpa.properties.hibernate.format_sql=true spring.jpa.properties.hibernate.type=trace p6spy도 똑같이 하나만 나오더라구요
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. [질문 내용] 오류 내용 application.yml Member MemberRepository MemberRepositoryTest Mysql 접속으로 변경 ddl-auto: create @GeneratedValue 위와 같은 조건으로 수행했는데 usermember_seq 테이블을 생성하지 못하고 존재 하지 않는 다는 오류가 발생합니다. 고민고민 하다 도저히 찾을수 없어 질문 드립니다.
제가 배웠던 JPA는 Member를 예로 들면 public interface MemberRepository extends JpaRepository<Member, Long> 이런 식으로 JpaRepository를 상속받아서 쓰는 것이었는데, 영한님 강의 초반부 수강 중인데 이런 내용이 없더라구요..! 강의 뒷부분에 이런 내용이 나오나요? 아니면 이 방식은 사용하지 않으시나요?
안녕하세요 엔티티 연관관계에대해 공부하던 중 질문이 생겨 글 남깁니다! Order에서 주문이 들어가면 Item에있는 stockQueantity가 하나씩 줄어든다고 했는데 OrderItem->Item의 단방향 연관관계이면 Item에서는 어떤게 주문이 들어갔는지 어떻게 알고 하나씩 줄어드나요??