자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
연관관계의 주인은 곧 외래키를 갖고 있는 테이블이 그 연관관계의 주인으로 이해가 됩니다. SQL문의 create table을 통해서 보면 외래키가 명확하게 드러나서 연관관계의 주인이 누구인지 파악이 비교적 수월한데, JPA의 코드를 통해 보면 누가 관계의 주인인지 잘 모르겠습니다. 물론 그것을 파악하기 쉬우라고 mappedBy를 이용해서 주인이 아니라는 것을 표시한다는 것은 알겠는데, 만약 이것이 안적혀 있더라도, 코드만 보고 관계의 주인을 파악하는 방법이 있을까요?
자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
package com.group.libraryapp.domain.user; import com.group.libraryapp.domain.user.loanhistory.UserLoanHistory; import javax.persistence.*; import java.util.ArrayList; import java.util.List; @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id = null; @Column(nullable = false, length = 20, name = "name") private String name; private Integer age; // ManyToOne의 관계이기 때문에 List 사용 @OneToMany(mappedBy = "user") // mappedBy는 연관관계의 주인이 아닌 쪽에 붙는다. private List<UserLoanHistory> userLoanHistories = new ArrayList<>(); protected User() { } public User(String name, Integer age) { if (name == null || name.isBlank()) { throw new IllegalArgumentException(String.format("잘못된 name(%s)이 들어왔습니다.", name)); } this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Long getId() { return id; } public void updateName(String name) { this.name = name; } } 궁금증은 간단합니다. updateName과 setName의 차이점이 무엇인지 궁금합니다. updateName 또한 setName 처럼 User 객체의 name 프로퍼티를 변경해주기 위한 메서드로 보입니다. 이름만 다를 뿐 형태가 똑같은데 굳이 updateName 이란 메서드를 만드는 이유가 궁금합니다. updateAPI에 맞춰서 통일성을 주기 위해 updateName 메서드를 만든 것인지, update의 요구 조건에 따라 updateName이 변경될 가능성이 있기 때문에 확장성 때문에 만든건지 아니면 어떠한 이점이 있는 것인지 등등 그 목적이 알고 싶습니다.
안녕하세요 항상 강의 잘 보고 있습니다. 영한님께서 알려주신 내용으로 공부와 토이프로젝트를 병행해나가다 이해가 가질 않는 부분이 있어서 질문드립니다. 상황 A클래스에 @PostConstructor 어노테이션을 붙여 객체 a를 미리 저장해 DB에 저장을 하고 B클래스에도 @PostConstructor를 붙여 객체 b를 저장하려 하였습니다. (A클래스와 B클래스의 연관관계는 일대다입니다.) a객체에 b객체를 리스트 형태로 저장할 수 있게끔 빈 리스트를 만들어 저장하는 것까지 A클래스에서 확인을 하였고 B클래스에서 b객체를 만들고 아까 저장한 a객체를 DB에서 가져오는것까지 확인하였습니다. 이후 a객체와 b객체의 연관관계를 연관관계 편의 메서드로 만들어주려하였으나 a객체에서 b객체들을 담을수 있게끔 만들어둔 리스트 형식의 필드가 lazyinitializationexception 예외를 발생시키며 더미데이터 생성에 실패하였습니다. 시도해 본 것들 @OneToMany의 기본 로딩 전략이 지연로딩이기에 생긴 문제인가 싶어 em.flush, @GraphEntity, hibernate.initialize까지 해보았으나 똑같이 lazyinitializationexception를 발생시키며 더미데이터 생성에 실패하였습니다. (혹시나 해서 즉시로딩으로 변경하니 더미데이터 생성은 문제없이 잘 되었습니다.) 궁금한 점 혹시 어떤 이유로 다음과 같은 현상이 발생했는지 알 수 있을까요?
안녕하세요 호돌맨님 ! 질문이 있습니다 !! Pageable 을 사용해서 페이징 구현 시 Full Scan 을 하기 위해 Count 쿼리가 발생하는걸 확인했는데, Pageable 에서는 페이징 처리를 위해 총 데이터의 개수를 파악해야 하기 때문이니까 Count 쿼리가 필요한거고 Querydsl 은 직접 limit 값, offset 값을 지정하기 때문에 Full Scan 할 필요가 없으니 Count 쿼리가 필요없는게 맞을까요 ?
@PostMapping("members/new") public String create(String name){ Member member = new Member(); member.setName(name); MemberService.join(member); return "redirect:/"; } 위 코드처럼 String을 이용해 form에서 데이터를 받아오면 안 되는 건지 궁금합니다
며칠전 수강시작했구요. 첫 완강한 인프런 유료강의가 되었네요. 앞으로도 이러한 스타일 (주제중심, 적당한 총 길이)의 강의를 더 만들어주시면 감사하겠습니다. 업무환경에서 다양한 기술스택을 경험하기 어려운 개발자들도 경험하면 좋을 기술스택도 좀 포함되면 더할나위 없이 좋을것 같구요. 제 경우엔 이 강의 덕분에 아주 오래전 살짝 경험해본 Redis 를 복습하게 되었고, Kafka 에 대해서도 입문하게 되었습니다. 질문드립니다. 이 강의에서 Kafka 이용의 장점은 처리량 조절이라고 말씀주셨습니다. 처리량 조절의 구체적인 방안은 구성방식, 요건등 상황에 따라 다양한 안이 있긴 하겠지만 혹시 알려주실만한 방안이 있을까요? 개인적으로 찾아본것은 컨슈머 옵션중 fetch.max.wait.ms 또는 fetch.max.bytes 같은 옵션을 이용하면 괜찮겠다라는 생각이 들긴 했습니다. (쓰면서 생각드는건데.... 만약 두개 동시에 이용시 OR 조건으로 동작해야 될텐데.. 라는 생각이...) 경험하신 사례이든, 참고할만한 링크이든 혹시 알려주실수 있다면 감사하겠습니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 1. 애플리케이션이 실행될 때, @Controller annotation이 있는 HomeController class의 instance가 스프링 컨테이너에 bean으로서 등록 2. 사용자가 localhost:8080 입력하면 tomcat 서버가 받고, 스프링 컨테이너에 @GetMapping("/")이 있는 bean 탐색 3. HomeController class 내부에 있는 home()이 @GetMapping("/")이 있고, 문자열 "home"을 return하므로 templates 폴더에 있는 home.html 렌더링됨, 컨테이너에서 이미 대응되는 bean을 찾았으므로 static 폴더에 있는 index.html는 렌더링 X 이 과정이 맞을까요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 여기에 질문 내용을 남겨주세요. package hello.hellospring.service; import hello.hellospring.domain.Member; import hello.hellospring.repository.MemoryMemberRepository; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.*; import static org.junit.jupiter.api.Assertions. assertThrows ; public class MemberServiceTest { MemberService memberService; MemoryMemberRepository memberRepository; @BeforeEach public void beforeEach() { memberRepository = new MemoryMemberRepository(); memberService = new MemberService(memberRepository); } @AfterEach public void afterEach() { memberRepository.clearStore(); //코드가 끝날때마다 clear @Test void 회원가입() { // given Member member = new Member(); member.setName("hello"); // when long saveId = memberService.join(member); // then Member findMember = memberService.findOne(saveId).get(); Assertions. assertThat (member.getName()).isEqualTo(findMember.getName()); } @Test public void 중복_회원_예외() { // given Member member1 = new Member(); member1.setName("spring"); Member member2 = new Member(); member2.setName("spring"); // when memberService.join(member1); //then IllegalStateException e = assertThrows (IllegalStateException.class, () -> memberService.join(member2)); Assertions. assertThat (e.getMessage()).isEqualTo("이미 존재하는 회원입니다."); } // //then // try{ // memberService.join(member2); // fail(); // }catch (IllegalStateException e){ // // assertThat을 통해 두 객체가 같은지 확인한다. // Assertions.assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.1232131"); // } @Test void findMember() { } @Test void findOne() { } }
안녕하세요~ 예전에 TC 를 작성하면서 발생한 궁금점들이 이번 강의를 통해서 다시 한번 생기게 되어서 질문 올리게 되었습니다!! UserSerivce 를 Test 하기 위해 UserRepository 모킹주입을 하였습니다. 이 때, stub 을 사용하여 모킹 객체의 동작을 정의해주는데, 제가 예전에 이렇게 했을 때 (강의 예제와 같은) UserRepository 의 동작을 일괄적으로 관리하기 위해 @BeforeEach 를 사용하였습니다. | 이렇게 했더니 실제로 많은 일을 수행하는 Repository 에 들어가는 when 절이 정말 많아지고 BeforeEach 가 매우 길어져서 ( 필요한 연관 객체들 User 와 연관된 A,B,C 등의 Entity 모두 그 때 그 때 생성해주는 코드까지 다 결합 되어 있었음), 이게 과연 맞는가? 싶은 생각이 들었습니다. 해당 강의를 통해서 그냥 그렇게 하는게 맞았었나보네 싶은데 , 보통 그렇게 BeforeEach 혹은 각 TC 코드가 길어져도 이렇게 Test 하는게 관례적인 모습일까요? 그간 물어볼 사람이 없어서 못 물어봤는데 이렇게 질문드릴 수 있게 되어서 다행입니다 ㅠ
33강 하고 있는데요..디비 설정부분에서 에러가 납니다. 데이터소스 설정이 안되어있다고 하는거 같은데...몇 번을 뒤져봤는데도 제 눈에는 안 보네요..ㅠ Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured. Reason: Failed to determine a suitable driver class Action: Consider the following: If you want an embedded database (H2, HSQL or Derby), please put it on the classpath. If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active). build,gradle의 디펜던시입니다 dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' testImplementation 'org.springframework.boot:spring-boot-starter-test' runtimeOnly ' com.oracle .database.jdbc:ojdbc8' } 의존성은 dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' testImplementation 'org.springframework.boot:spring-boot-starter-test' runtimeOnly 'com.oracle.database.jdbc:ojdbc8' } persistence 설정은 아래와 같습니다.. <properties> <property name="jakarta.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver" /> <property name="jakarta.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:xe" /> <property name="jakarta.persistence.jdbc.user" value="scott" /> <property name="jakarta.persistence.jdbc.password" value="tiger" /> <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle12cDialect" />
안녕하세요. 강의 잘 듣고 있습니다. BatchSize라는 기능을 배워서 상당히 놀라웠는데요. 해당 기능을 사용해 실행되는 쿼리를 보니 IN (?, ?)와 같이 바인딩 변수를 이용하는 것으로 보이는데 만약 말씀하신것처럼 BatchSize를 1000개로 잡았다 할 떄 최악의 경우 IN절 내부의 ? 바인딩 변수가 계속 변하게 된다면 (1개 ~ 1000개 ) 소프트 파싱의 이점을 살리지 못하는 경우가 발생할 수도 있나요 ?? 항상 좋은 강의 만들어주셔서 감사합니다
안녕하세요 UI와 GetMapping API 테스트를 하는데 로컬에서 테스트 할 때는 잘 되는데 API 테스트를 하면 아래와 같이 Required request body 에러가 뜹니다. Client에서 보낸 JSON데이터를 로컬에서 테스트 하면 잘 되는데 GetMapping 만 쓰는 API에서는 @RequestBody 가 안되는걸까요..? (비슷한 내용의 코드인데 GetMapping, PUTMapping, POSTMapping이 있는 API에서는 또 잘되고 있어서 이런의문점이 듭니다.) 아래 코드와 에러 내용 드립니다. . 코드 (Parameter 명과 Class명 수정했습니다.) @Slf4j @RestController @RequestMapping(value = "/", method = RequestMethod. GET ) public class SchoolController { @Autowired ClassService cs; @GetMapping("/School") public List<Event> School( @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @RequestBody Class class ) throws Exception { List<Class> ClassList = new ArrayList<Class>(); ClassListt = cs.selectClassBySearchCriteria(class.getId(), class.getName(), class.getCreateTime(), class.getUpdateTime()); } . 에러내용 Resolved [org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public java.util.List<mes.sdc.mads.vo.Event> mes.sdc.mads.controller.DetectionController.anomalyEvent(mes.sdc.mads.vo.Event,org.springframework.ui.Model) throws java.lang.Exception]
[질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 네 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 있는데 설정해도 안됩니다,, 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 네 [질문 내용] 프로젝트 생성 강의에서 압축받아온 프로젝트파일을 열었으나 실행버튼이 활성화되지 않음 문제화면 -> 오른쪽 위 노란 네모박스 옆에 서버도 연결이 안되는거같습니다.. build.gradle 에서는 자바 17버전이 필요하다는거같은데, 혹시 위에있는 11버전을 전부 17버전으로 바꿔야하나요? 오류 내용을 봐도 버전 문제인 것 같아서요..
Iterm을 통해서 권한을 주는 부분 h2 데이터베이스 버전은 스프링 부트 버전에 맞춘다. 권한 주기: chmod 755 h2.sh (윈도우 사용자는 x) 실행: ./ h2.sh (윈도우 사용자는 h2.bat) 데이터베이스 파일 생성 방법 jdbc:h2:~/test (최초 한번) ~/ test.mv .db 파일 생성 확인 이후부터는 jdbc:h2:tcp:// localhost/~/test 이렇게 접속 이 부분.. 잘 안됩니다 경로도 다르고 해서 해결이 잘 안되는데 좀 도와주시면 감사하겠습니다ㅠㅠ