묻고 답해요
160만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
실무에서 테스트 케이스 작성 시
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]안녕하세요, 강의 수강 잘 하던 도중 질문이 생겨 여쭤봅니다. 강의에서는 Service 계층에서만 테스트를 하고 있고 Repository 계층에서는 따로 진행하지 않고 있습니다.실무에서도 어차피 Service 계층이 Repository 계층을 당겨서 사용하는 것이기에 Service 계층에 대해서만 테스트 케이스를 작성하면 충분할까요 ?그리고 강의에서 Member의 Name을 unique로 잡으라고 말씀하시고 있는데, 실무에서는 id로 검증하는 것이 올바른 방법이겠죠 ?
-
미해결코드로 배우는 React 19 with 스프링부트 API서버
로그인 관련 커스텀 훅 만들기 -> 부분 질문입니다.
현재 loginSlice.tsx에서 오류가 나고 있습니다..아래와 같은 메세지를 접했습니다.useCustomLogin.tsx:2 Uncaught SyntaxError: The requested module '/src/store.tsx' does not provide an export named 'AppDispatch' (at useCustomLogin.tsx:2:10) 어느부분을 손 봐야할까요?vite 6.3버전으로 이용하고 있습니다. loginSlice.tsximport { createAsyncThunk, createSlice } from "@reduxjs/toolkit" import { loginPost } from "../api/memberApi" import { removeCookie, setCookie } from "../util/cookieUtil" export interface LoginInfo { email:string, nickname:string, accessToken: string, refreshToken: string, roleNames: string[], status: string } const initState:LoginInfo = { email: '', nickname: '', accessToken:'', refreshToken: '', roleNames: [], status: '' } export const loginPostAsync = createAsyncThunk('loginPostAsync', ({email, pw}: {email:string, pw:string}) => { console.log("---------------loginPostAsync---------------------") console.log(email, pw) return loginPost(email, pw) }) const loginSlice = createSlice({ name: 'loginSlice', initialState: initState, reducers: { save: (state, action) => { console.log("save...........") return action.payload }, logout: (state, action) => { console.log("logout..........") removeCookie("member") } }, extraReducers :(builder) => { builder.addCase(loginPostAsync.fulfilled , (state, action) => { console.log("loginPostAsync.fulfilled") const newState:LoginInfo = action.payload newState.status = 'fulfilled' setCookie("member", JSON.stringify(newState), 1) return newState }) .addCase(loginPostAsync.pending, (state, action) => { console.log("loginPostAsync.pending") state.status = 'pending' }) .addCase(loginPostAsync.rejected, (state, action) => { console.log("loginPostAsync.rejected") state.status = 'rejected' }) } }) export const { save, logout} = loginSlice.actions export default loginSlice.reducer useCustoLogin.tsximport { useDispatch, useSelector } from "react-redux" import { AppDispatch, RootState } from "../store" import { Navigate, useNavigate } from "react-router" import { loginPostAsync, logout, save } from "../slices/loginSlice" import { useEffect } from "react" import { getCookie } from "../util/cookieUtil" const useCustomLogin = () => { const dispatch = useDispatch<AppDispatch>() //로그인 상태 객체 const loginState = useSelector((state: RootState) => state.loginSlice) //로그인 여부 const loginStatus = loginState.status //fulfilled, pending, rejected useEffect(()=> { if(! loginStatus ) { const cookieData = getCookie("member") if(cookieData){ dispatch(save(cookieData)) } } }, []) const navigate = useNavigate() const doLogin = async (email:string, pw:string) => { dispatch(loginPostAsync({ email, pw })) } const doLogout = () => { dispatch(logout(null)) } const moveToLogin = () => { navigate("/member/login") } const moveToLoginReturn = () => { //--------로그인 페이지로 이동 컴포넌트 return <Navigate replace to="/member/login"/> } const moveToPath = (path:string) => { //----------------페이지 이동 navigate({pathname: path}, {replace:true}) } return {loginState, loginStatus, doLogin, doLogout,moveToLogin,moveToLoginReturn,moveToPath} } export default useCustomLogin store.tsximport { configureStore } from "@reduxjs/toolkit"; import loginSlice from "./slices/loginSlice"; const store = configureStore({ reducer: { "loginSlice": loginSlice, } }) export type AppDispatch = typeof store.dispatch export type RootState = ReturnType<typeof store.getState> export default store
-
미해결자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
과제를 위한 초기세팅
안녕하세요 과제를 하나씩 만들고있는데 4일차 과제인 api만들기를 하려고합니다! 그전까지는위처럼 기존 강의 초기세팅 된곳에 hw폴더를 만들어서 하고있는데 이렇게 말고 강의초반에 배운대로 spring.io에서 초기세팅을 새로해서 과제를 위한 스프링부트 프로젝트를 새로 만들고싶은데요..! 혹시 현재 강의 초기세팅과 같이 하려면 어떻게해야될지 알려주실 수 있으신가요? 1~2강 초기세팅 강의에서 spring.io로 처음부터 만드는걸 배울때 자바나 스프링부트 버전설정이런건 설명이 있었는데 그다음 의존성 이런건 나중에 설명이 나온다했던거같아서 정확히 모르겠습니다.강의에 혹시 있다면 어디를 참고하면 될지만이라도 알려주시면 감사드리겠습니다!!
-
미해결토비의 클린 스프링 - 도메인 모델 패턴과 헥사고날 아키텍처 Part 1
안녕하세요. 토비님! 도메인의 다양한 업데이트 요구사항을 Web API 계층에서 어떻게 다뤄야 할까요?
안녕하세요, 토비님. 강의를 들으며 많은 인사이트를 얻고 있습니다.강의를 완강한 후에도 내면적으로 정리되지 않은 부분이 있어 조심스럽게 질문을 드리게 되었습니다.생성과 관련된 설계는 강의에서 잘 이해가 되었지만, 업데이트(update)와 관련된 내용은 직접적으로 다뤄지지 않아 고민이 생겼습니다. 특히, 제 고민은 다음과 같습니다."도메인의 비즈니스 규칙이 Web API 설계에 어느 정도까지 직접적으로 드러나야 하는가?"현재 도메인 로직에서는 사용자의 여러 정보를 변경할 수 있는 비즈니스 규칙이 존재합니다. 예를 들어:비밀번호 변경 기타 세부정보 변경비즈니스적으로는 각각의 규칙이 잘 정의되어 있고, 각각의 변경 로직도 Member 객체 내에 명확히 메서드로 존재합니다.여기서, 이러한 비즈니스에 대해서 API에 어떻게 노출시켜야 하는가에 대해서 두 가지 선택지가 고려됩니다.1. 비즈니스 정의를 역할 별로 구성한다.POST /api/v1/members/{id}/change-password POST /api/v1/members/{id}/change-nickname생각이 나는 장단점은 다음과 같습니다.장점: 비즈니스에 따라 API를 관리하여 클라이언트가 이해하기 용이합니다.단점: 수정 가능한 필드가 많아질수록 API의 개수가 증가하며, 유지보수가 어려워질 수 있고, Restful 규칙에 위배됩니다.2. 하나의 update API로 통합한다.PATCH /api/v1/members/{id} { "password": "originalPassword123!", // nullable "detailRequest": { // nullable "email": "user@example.com", "nickname": "nickname123", "password": "newPassword456!" } }장점: API가 간결하여 확장이 용이하며, 클라이언트는 필요한 값만 상황에 따라 요청하면 됩니다.단점: API가 비즈니스 책임에 명확하지 않을 수 있습니다.결론적인 질문은 다음과 같이 정리 할 수 있을 것 같습니다.비즈니스 로직이 도메인 레이어에 잘 분리되어 있는 경우, API 계층에서도 분리하여 표현하는 것이 좋은가요?도메인의 역할만 명확하다면 API는 통합해서 update 형식으로 만들어도 괜찮은가요?만약, 후자로 처리를 한다면 어디서 처리를 하는게 좋아보이시나요?서비스 계층도메인 계층// MemberModifyService public void update(Long memberId, MemberUpdateRequest request) { Member member = memberFinder.find(memberId); if (request.password() != null) { member.changePassword(request.password()); } if (request.detailRequest() != null) { member.updateInfo(); } } -------- // MemberModifyService public void update(Long memberId, MemberUpdateRequest request) { Member member = memberFinder.find(memberId); member.update(request); } // Member public void update(MemberUpdateRequest request) { if (request.password() != null) { changePassword(request.password()); } if (request.detailRequest() != null) { updateInfo(); } }뭔가, 이런 고민이 계속 드는 이유가 외부 계층에 종속적이지 않고 도메인에 의존하여 개발을 하더라도 실제로 저희가 처한 상황은 대부분 WebAPI 계층에서의 요청이 많다보니 외부의 행위 또한 도메인에 종속되어야 하는가 하는 고민이 생긴 것 같습니다. 양질의 강의 제공해주셔서 감사드립니다!
-
미해결토비의 클린 스프링 - 도메인 모델 패턴과 헥사고날 아키텍처 Part 1
@NaturalIdCache에 대한 보충 설명 및 사용법 공유
'25. 엔티티의 자연키 지정' 영상의 후반부에 적용한 @NaturalIdCache에 대해 추가로 학습한 내용이, 저처럼 해당 애노테이션을 처음 접한 분들에게 도움이 될 것 같아서 글을 작성합니다. 강의에서 오해가 있을 수 있는 부분, 그리고 자연키에 캐시를 적용하는 방법을 정리해 보았습니다. 강의 내용과 실제 동작의 차이점강의에서는 “같은 트랜잭션 안에서 같은 아이디 값을 가지고 여러 번 조회 시 Persistence Context 에 캐시된 값을 꺼내오는 것 처럼. @NaturalIdCache를 적용하면 이것도 영속 컨텍스트에 캐싱이 된다.”고 말씀하셨습니다. 해당 내용에 대한 이해를 돕기 위해 Hibernate의 두 가지 캐시에 대해 간단히 짚고 넘어가겠습니다.1차 캐시 (First-Level Cache): 세션(영속성 컨텍스트) 범위의 캐시입니다. 같은 트랜잭션 안에서만 유효하며, 트랜잭션이 끝나면 사라집니다. Spring Data JPA에서는 기본적으로 @Id 에 대한 조회를 1차 캐시합니다. 2차 캐시 (Second-Level Cache): 세션 팩토리 범위의 캐시로, 여러 세션에서 데이터를 공유할 수 있습니다. 적용하려면 별도의 의존성 추가 및 캐시 관련 설정(@Cache 등)이 필요합니다. 따라서, "같은 트랜잭션 안에서 캐시된 값을 꺼내온다."는 말은 세션 범위의 1차 캐시로 해석됩니다. 하지만 제가 직접 테스트해 본 결과, @NaturalIdCache는 1차 캐시가 아닌 2차 캐시와 관련이 있었으며, 1차 캐시를 적용하기 위해서는 다른 방법이 필요했습니다. 테스트를 통한 확인자연키에 대한 1차 캐시 동작을 확인하기 위해, 강의에서 적용한 Member 엔티티의 @NaturalIdCache 를 제거하고, 자연키(Email)에 @NaturalId만 적용한 상황에서 두 가지 방식으로 테스트를 진행했습니다. 테스트1: findByEmail 메서드를 사용한 조회Java@Test void NaturalIdFirstLevelCache() { Member member = Member.register(createMemberRegisterRequest(), createPasswordEncoder()); memberRepository.save(member); entityManager.flush(); entityManager.clear(); System.out.println("회원 저장 및 persistence context 초기화 완료"); // 같은 email(Natural ID)로 두 번 조회 Member findMember1 = memberRepository.findByEmail(member.getEmail()).get(); Member findMember2 = memberRepository.findByEmail(member.getEmail()).get(); assertThat(findMember1).isSameAs(findMember2); } Spring Data의 쿼리 메서드를 사용하여 이메일로 조회하는 findByEmail 메서드를 만들고, 한 트랜잭션에서 같은 회원을 두 번 조회했습니다. 자연키에 대한 1차 캐시가 동작한다면, SELECT 쿼리는 한 번만 실행되어야 합니다.결과는 SELECT 쿼리가 두 번 실행되었습니다. 즉, 자연키에 대한 1차 캐시가 동작하지 않았습니다. 테스트2: Hibernate의 자연키 관련 API를 사용한 조회@NaturalId를 다루는 글들을 찾아본 결과 Hibernate가 제공하는 자연키 관련 API가 있다는 것을 확인했고, 이를 적용하기 위해 커스텀 리포지토리를 구현했습니다.Java@Repository @RequiredArgsConstructor public class CustomizedMemberRepositoryImpl implements CustomizedMemberRepository { private final EntityManager entityManager; @Override public Optional<Member> findByNaturalId(Email naturalId) { return entityManager.unwrap(Session.class) .bySimpleNaturalId(Member.class) .loadOptional(naturalId); } } 그리고, 테스트 1과 같은 방식으로 테스트를 진행하였습니다. @Test void NaturalIdApi() { Member member = Member.register(createMemberRegisterRequest(), createPasswordEncoder()); memberRepository.save(member); entityManager.flush(); entityManager.clear(); System.out.println("회원 저장 및 persistence context 초기화 완료"); Member findMember1 = memberRepository.findByNaturalId(member.getEmail()).get(); Member findMember2 = memberRepository.findByNaturalId(member.getEmail()).get(); assertThat(findMember1).isSameAs(findMember2); }결과는 SELECT 쿼리가 한 번만 실행되었습니다. 이를 통해 자연키에 대한 1차 캐시는 @NaturalIdCache 애노테이션과 무관하게, 전용 API를 사용해야만 동작하는 것을 확인했습니다. @NaturalIdCache의 용도@NaturalIdCache Javadoc에는 다음과 같은 설명이 있습니다.Specifies that mappings from the natural id values of the annotated entity to the corresponding entity id values should be cached in the shared second-level cache.…중략This annotation is usually used in combination with Cache, since a round trip may only be avoided if the entity itself is also available in the cache.대략 “natural id와 상응하는 id에 대한 매핑을 2차 캐시에 저장하는 애노테이션이고, 엔티티가 캐시되어있어야 하기 때문에 일반적으로 Cache와 함께 사용된다.”라고 해석됩니다. 즉, 1차 캐시가 아닌 2차 캐시를 위한 애노테이션입니다. 정리2차 캐시 관련 설정 및 테스트를 마저 진행한 후 최종 정리한 내용은 다음과 같습니다. 자연키의 1차 캐시@NaturalIdCache 애노테이션과 관련 없습니다. 자연키에 @NaturalId만 붙이면 됩니다.반드시 Hibernate Session의 bySimpleNaturalId() 같은 전용 API를 사용해야 적용됩니다. 자연키의 2차 캐시@Cache와 @NaturalIdCache를 함께 사용해야 동작합니다.@Cache만 사용 시 @Id로 조회할 때만 2차 캐시가 동작합니다.@NaturalIdCache만 사용 시 자연키와 ID에 대한 매핑 정보는 캐시 히트되는 걸 확인했지만, ID와 엔티티에 대한 캐시가 없어서 캐시가 적용되지 않았습니다. @Cache와 @NaturalIdCache 모두 사용 시 ID를 통한 조회와 자연키를 통한 조회 모두 2차 캐시가 적용됩니다. 참고 자료Hibernate6.6 공식 문서NaturalCache javadocsbaeldung: Hibernate Natural IDs in Spring BootSpring Custom Repository 글의 오류나 부족한 내용을 알고 계신 분은 코멘트를 달아주시면 감사하겠습니다.
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
test 케이스 결과 실패
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. JPA와 DB 설정, 동작확인 과정에서 3version으로 pdf 파일보고 설정했는데 test 결과가 실패합니다... 원인을 모르겠습니다
-
미해결토비의 스프링 6 - 이해와 원리
상태 변경 API 질문
안녕하세요토비님 강의 듣고나서 제 나름대로 API 서버 제작 연습을 좀 해보도가 JPA 및 도메인 상태 변경에 관련해서 질문 드리고 조언을 얻고자 문의 드립니다.상황은 아래와 같습니다.DDD에 입각하여 Aggregator 가 하위 Entity Life Cycle 담당Entity 식별자 타입 경우 LongClient 에서 변경 API 요청 시 Aggregator 의 식별자는 존재하지만, 하위 Entity 에 대한 id 는 포함하지않은채 요청{ id: AggregatorId name: AggregatorName list: [ { name: 'modified name1', type: 'type1', status: 'active' }, { name: 'modified name2', type: 'type2', status: 'inactive' }, { name: 'new name3', type: 'type3', status: 'active' } ] } id 가 없이 JPA 변경 요청 시 delete-insert 가 진행 될것 같아 자체적으로 key based diff 라는 함수를 제작하여 변경점과 신규 데이터에 대해서 병합 후 save() 를 호출 할 것같은데 이럴 경우 insert, update 문의 별도로 나가지 않을까 생각이 듭니다.이런 경우 DB 입장에서 하나의 트랜잭션에서 수행하더라도 부하나 성능에 악영향을 미칠 것 같은데 이럴 경우 어떤식으로 애플리케이션 로직을 세우고 JPA 를 어떻게 활용해야되는지 조언 부탁드려도될까요?참고로 저는 하위 Entity 변경 시 batchUpsert 를 고려하고 있습니다.
-
미해결토비의 클린 스프링 - 도메인 모델 패턴과 헥사고날 아키텍처 Part 1
jpa/도메인 엔티티 분리에 대한 궁금한 점이 있습니다.
토비님 안녕하세요. 강의 너무 즐겁게 잘 수강하고 있는 한 개발자 입니다.강의 수강 중에 궁금한 점이 생겨서, 토비님의 의견이 궁금해서 한 가지 질문 드리고자 합니다.33. 엔티티 클래스와 JPA 매핑 정보 분리강의에서 분리를 xml로 분리해서 매핑 하는 예를 들어주셔서, 이 부분에 대해서 궁금한 점이 있습니다. 개인적으로 xml 매핑작성 생산 비용과 jpa/도메인 엔티티를 분리해서 작성하는 비용이 크게 차이나지 않는것 같단 생각이 들긴합니다. 결국 xml이든, 코드든 분리해서 작성 비용이 필요한 것 같아요.그렇다면, 여기에서 관리 포인트를 이중(xml,코드)으로 가져가는게 나을지, jpa/도메인 엔티티를 분리해서 코드에서 관리하는게 나을지? 고민이 되는데요. 토비님의 의견은 어떠신지 궁금합니다.ai 자동완성 기능 활용코드도 마찬가지로, 애노테이션 빼줘, 붙여줘 하면 어느정도 잘 만들어주긴 하더라구요. 이 부분도 어떻게 생각하시는지 궁금합니다.코파일럿에 xml 매핑정보 만들어줘 하는 내용과, 코드로 애노테이션 붙여줘, 빼줘 해서 복/붙하는 행위 자체가 크게 다르지 않은것 같다는 생각이 들긴해서 이 부분은 어떻게 생각하시는지도 궁금합니다.유지보수 관점에서생산비용 보다, 개발 완료 후 유지보수를 하는데 있어서 그래도 xml/코드 두가지 중 1개를 선택해야한다면 어떻게 관리하는것이 나을까요?? 바쁘신 와중에도 질문 확인하고 답변 주시는 점 미리 감사드립니다.
-
미해결코드로 배우는 React 19 with 스프링부트 API서버
mallapi
mallapi에서 malldb를 연결 했고,apiserver에서 apidb를 연결했습니다.4강 조회기능에서test를 위해 malldb에 테이블 확인을 하시는데 왜 갑자기 테이블이 생긴걸까요?저희는 mallapi는 연결만 하고 구현은 안된거 아닌가요?apiserver에서 구현한 todo는 apidb 안에서 생성되는 걸로 구현이 되어있는데뭘 잘못 한건가요?
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
외래키가 없는 일대일 관계에서의 연관관계 주인 설정
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]안녕하세요, 질문이 생겨 여쭤봅니다.외래키가 있는 곳을 연관관계의 주인으로 설정하라 하셨는데, 만약 외래키가 없는 두 엔티티가 1대1 관계라면 이때는 랜덤으로 연관관계의 주인을 설정하면 되는 것일까요 ?
-
미해결토비의 클린 스프링 - 도메인 모델 패턴과 헥사고날 아키텍처 Part 1
안녕하세요! 강의 완강했습니다! 혹시 다음 강의는 대략적으로 언제 오픈 될까요?
안녕하세요! 강의 완강했습니다! 혹시 다음 강의는 대략적으로 언제쯤 오픈 될까요?
-
미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
컬렉션값 명시적 조인 질문드립니다
안녕하세요. 컬렉션값 명시적 조인에 대해서 select t.members.username from Team t 는 실패하고, select m.username from Team t join t.members m 은 성공한다고 하셨는데, 여기서 해당 jpql을 실행했을때 변환되는 SQL에 대해서 이해가 가지않는 부분이 있어서 구글링을 통해 찾아보면서 아래와 같이 정리해봤는데, 이렇게 이해하는게 맞을까요?? select t.members.username from Team t 형태로 하면 안된다. 대신에 select m.username from Team join t.members m 형태로 해야한다. select m.username from Team join t.members m를 실행하면 SELECT m.username FROM team t JOIN member m ON t.id = m.team_id 쿼리로 변환되서 실행된다.여기서,1.t.members가 member로 변환되는 이유는 컬렉션 필드 members의 제네릭 타입이 Member이기 때문이다. t.members는 Team 객체가 갖는 List<Member> 컬렉션이다. 이 컬렉션은 결국 Member 엔티티에 해당하는 테이블, 즉 member 테이블의 여러 행들을 의미한다. 따라서 JPA는 join t.members를 Member 엔티티 대상으로 join하는것으로 해석하고, SQL에서는 member 테이블로 변환된다. 2.ON t.id = m.team_id가 추가되는 이유는 Team의 members와 Member의 team이 연관관계인 상태이기 때문이다. 3.from 뒤에는 엔티티객체만 적을수 있는데, join 뒤에는 엔티티객체뿐만 아니라 엔티티객체의 연관필드도 적을수 있다. 하지만 이때는 반드시 경로표현식 형태인 .을 통해 나타내야한다.
-
해결됨토비의 클린 스프링 - 도메인 모델 패턴과 헥사고날 아키텍처 Part 1
도메인 모델의 화살표는 특별한 의미가 있을까요?
draw.io에서 도메인 모델을 설명해주시는 부분에 대해서 질문드립니다.도표의 다른 선들은 모두 화살표가 없는데, 수강은 회원과 강의 모델로 화살표가 있어서 어떤 의미인지 궁금합니다.
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
JUnit5 테스트시 DB 구동
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]현재 주문 기능 테스트에서 JUnit5를 이용하여 테스트 중입니다. 앞선 강의(회원 기능 테스트)에서 JUnit으로 테스트할때 메모리 DB 사용한다고 application.yml 을 test 쪽에 복사해서 사용할때도 url: jdbc:h2:mem:testdb 부분을 주석해도 돌아간다고 했었던 것으로 기억이 납니다. 그래서 TEST 시에는 DB를 연결 안해도 무방하다고 생각하고 있었는데요.오늘 주문 기능 테스트시 DB 끄고 했더니 에러가 나서 DB 연결했더니 정상적으로 동작합니다. TEST에서도 DB를 연결해주어야 하는 걸까요?
-
미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
기본 키 매핑
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]jpa 를 사용할때 id 값으로 영속성 컨텍스트를 분별하는데 사용하기 떄문에 persist 할때 미리 insert 쿼리를 사용하는걸로 알고 있는데 그럼 다른 트랜잭션 단위에서 동일한 행위를 하면 이미 auto_increment로 값이 올라가 있는 상태에서 다른 트랜잭션 작업 단위가 rollback 하게 되면 그럼 auto_increment 가 중간에 값이 비게 되는건가요? 비게 된다면 데이터가 삭제되거나 문제가 있다고 인식할수 있을것 같은데? 이럴때는 어떻게 하나요?
-
미해결스프링부트를 이용한 웹 프로그래밍: 웹사이트 이렇게 만드는 거예요!
인터셉터
스프링 시큐리티를 적용하고 나서 modify가 계속 /member/signin으로 리다이렉트 되는 현상이 발견되었는데, 원인을 파악해보니 인터셉터 클래스 문제였습니다.(기존 인터셉터 클래스에선 session을 기반으로 로그인 상태여부를 확인하는데, Spring Security를 사용하고 나선, session이 아닌 SecurityContext에 로그인 정보를 보관하니 서로 충돌을 일으켜 계쏙 signin으로 리다이렉트 되는거 같습니다.) 혹시 이 부분이 맞는지 확인 부탁드리며, 제가 쓴 내용이 맞다면, 강의 내용중에 이부분을 짚어주셨으면 합니다.
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
커리큘럼 방향에 대해서...
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오) 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 예[질문 내용]스프링핵심원리HTTP웹기본지식MVC1편스프링DB 1편수강완료 했고ORM표준JPA프로그래밍 완강 목표로 수강중입니다.혼자 프로젝트를 하나 만들어보고 싶은데JPA활용1편까지는 수강을 하고 시작하는게 좋을까요?아니면 실전 스프링 데이터 JPA를 수강하는게 좋을까요?
-
미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
안녕하세요 라우트 과정에서 http프로토콜 -> lb 프로토콜 질문 있습니다.
기존에는 http://localhost:8081 과같이 보내줬는데, 이걸 lb:/MY-FIRST-SERVICE로 바꿨습니다.그렇다면, 원래 localhost:8081로 직접 http 프로토콜로 보내줬던건, 유레카를 거치지 않았고, 하드코딩으로 직접 보내줬던 것이고, 그리고 lb:/를 이용하는 것이 유레카에 저장되어 있는, 정보들을 통해 읽어와서 동적으로 보내주는 것으로 이해하였는데, 제가 이해한게 맞을까요?
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
h2 database에 member 테이블이 생성되지 않아요
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)네, jpa와 db 설정, 동작 확인 동영상 입니다.2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)아니요. 있는 내용인데 찾아보고 해결하지 못했습니다.3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)네[질문 내용]여기에 질문 내용을 남겨주세요.테스트 코드 실행 시 member 테이블이 생성되지 않습니다. ddl 설정은 create이고, 관련 설정 확인해도 못찾아서 문의 드려요.테스크 코드 맨 마지막에 로그를 찍어놨는데, 해당 로그가 찍히고 이 뒤에 테이블이 왜 drop될까요?도저히 모르겠습니다...ㅎ https://drive.google.com/file/d/1WT3dZ7HexApj0xAYZsFJSkKVpaSmGEFM/view?usp=sharing구글 드라이브 프로젝트 첨부 드립니다.
-
미해결스프링부트를 이용한 웹 프로그래밍: 웹사이트 이렇게 만드는 거예요!
DTO 관련
강의 열심히 듣고 있습니다. 다름이 아니라, DTO 관련 의구심이 들어서 질문 올립니다. 선생님께선 modifyConfirm 일때dto의 pw 값을 encode된 값으로 변경하셔서 entity로 넣으셨는데,String encodedPW = passwordEncoder.encode(memberDTO.getPw()); memberDTO.setPw(encodedPW) findedMemberEntity.setMemPw(memberDTO.getPw()); 위의 방법대로 하면, dto값이 변경이 되어 "단순 전달 객체"를 위배할 수 있으며, 간결성과 가독성이 떨어지는게 아닌가 싶어서요 아래와 같이 리펙토링 하면 조금 더 간결하게 되지 않을까요?if (optionalMember.isPresent()) { MemberEntity findedMemberEntity = optionalMember.get(); findedMemberEntity.setMemPw(passwordEncoder.encode(memberDTO.getPw())); ~~ return MODIFY_SUCCESS; }