묻고 답해요
158만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨스프링 DB 2편 - 데이터 접근 활용 기술
빈을 찾을수 없다는 오류가 뜨는데 둘러봐도 빈이 잘 등록된거 같은데 실행이 안됩니다.
이전 질문을 혼자 해결해보다 jdk를 다시 설치하고 적용하니 버전이 다르다는 오류는 해결이 되었는데 이제Description:Parameter 0 of constructor in hello.itemservice.config.MyBatisConfig required a bean of type 'hello.itemservice.repository.mybatis.ItemMapper' that could not be found.Action:Consider defining a bean of type 'hello.itemservice.repository.mybatis.ItemMapper' in your configuration.오류가 발생합니다 둘러보아도 빈 등록은 정상적인거 같은데 이유를 모르겠습니다. H2데이타베이스도 켜주었습니다.https://drive.google.com/file/d/1vIo1htfB2qY7yLUz-JfRT_LDdzO8bAeU/view?usp=drive_link질문글 파일의 드라이브 링크입니다.
-
해결됨개발자를 위한 컴퓨터공학 1: 혼자 공부하는 컴퓨터구조 + 운영체제
프로세스 상태
프로세스란 실행중인 프로그램이고 좀더 정확히 말하면 보조기억장치에 적재되어있다가 프로그램이 메모리에 적재되고 실행이 되면 이떄 이 프로그램은 프로세스라고 하는걸로 알고있습니다그리고 이 과정을 프로세스가 생성된다고 말하고있다고 하셧습니다 PCB는 이 프로세스가 생성될때 커널영역에 저장된다고 하셧는데 프로세스 상태에서 생성상태가 이해가 안갑니다프로그램이 실행이(=프로세스) 안되는데도 메모리에 적재되어 PCB를 할당 받을수가잇나요? 프로그램이 실행되었다는건 메모리에 적재된 상태고 PCB도 할당 받은 상태인데"생성 상태" 라는 단어가 아직 실행중이지 않는 상태라는 뜻인데 이 부분이 말이 안된다고 생각해서요애초에PCB는 프로세스가 생성될떄 같이 만들어지는 애인데말씀하신 내용을 들어오면생성상태는 프로그램이 실행중인 상태가 아니라 그냥 메모리에 적재되어있는 상태인거 아닌가요?그럼 프로세스가 아닌 단순한 프로그램이 메모리에 적재되어있는상태가 아닌지 , 그리고 그상태가 맞다면 PCB는 아직 할당되지 않는게 맞는게 아닌가요?
-
해결됨[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!
플러터 내 생성 시 file / directory의 차이
플러터 내 생성 시 file / directory의 차이가 궁금합니다. 어떨 때는 New에서 file을 생성하고 어떨 때는 directory를 생성해서요~
-
미해결[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!
toolchanin 에러가 발생합니다.
Android toolchain - develop for Android devices X Unable to locate Android SDK. Install Android Studio from: https://developer.android.com/studio/index.html On first launch it will assist you in installing the Android SDK components. (or visit https://flutter.dev/docs/get-started/install/windows#android-setup for detailed instructions). If the Android SDK has been installed to a custom location, please use flutter config --android-sdk to update to that location. Android SDK is up to date.Running Android Emulator hypervisor driver installer[SC] ControlService 실패 1062:서비스가 시작되지 않았습니다.[SC] DeleteService 성공[SC] 4294967201 오류가 발생하여 StartService이(가) 실패했습니다.Done 이런 오류는 어떻게 해결하나요?
-
미해결Three.js로 1인칭 3D 웹사이트 만들기
반발력을 0으로 해도 계속 튕겨져나갑니다..ㅜ
안녕하세요 늘 좋은강의 감사합니다.playerContactMaterial 에서 restitution을 0으로 뒀는데도 캐릭터가 엄청 튕겨지네요 ㅜplayer의 cannonMaterial도 playerCannonMaterial로 변경했는데 똑같이 엄청 통통 튕겨다닙니다...그래서 궁금해서 그냥 defaultContactMaterial의 반발력을 0으로 두고 전부 defaultMaterial을 적용해봐도 똑같이 전부 통통 튕겨 다니네요...영상에서도 보면 부딪힐 때 캐릭터가 뒤로 튕겨져 나가는거 보니 어쩔수 없는 현상인걸까요??...
-
미해결김영한의 실전 자바 - 중급 2편
섹션 7. onlyHash
hashCode만 오버라이딩으로 재정의하면 해시코드는 같아지지만, 결국 equals비교 Object의 것을 사용해서 실패하게 된다고 하셨습니다.그런데 MemberOnlyHash 클래스에서 equals를 재정의를 했다고 가정했을 때, 어떻게 MemberOnlyHash로 갈 수 있는 건가요?오버라이딩 되어서 우선권을 갖고있는 건 알고있습니다.이해가 안 가는 부분을 어떻게 말을 해야 할 지 조금 복잡하지만... 1번 코드MyHashSetV2 set = new MyHashSetV2(10); NoEqualsOnlyHash m1 = new NoEqualsOnlyHash("A"); set.add(m1);1번 코드에서 set에서 add를 호출합니다. 2 코드public boolean add(Object value) { LinkedList<Object> bucket = buckets[hashIndex(value)]; if (bucket.contains(value)) { return false; }그리고 2번 코드에 들어가게 되고 3번 코드 public boolean add(MemberOnlyHash m1) { LinkedList<Object> bucket = buckets[0]; if (bucket.contains(m1)) { return false; }그러면 2번 코드가 실행되면 3번 코드처럼 되는 거라고 이해하고 있습니다. (hashIndex는 편의상 0이라고 하겠습니다.) 0번 인덱스에 있는 LinkedList <Object> 타입의 연결리스트가 나옵니다. 다음으로 if문으로 들어갑니다. 그리고 LinkedList <Object> 타입의 연결리스트(bucket)가(이) m1을 포함하는지 contains 메서드를 통해서 확인합니다. 여기서 질문입니다.질문 1 : MemberOnlyHash 타입의 m1과 비교를 하는데 bucket은 여전히 Object타입입니다. (Object)bucket이 contains를 사용하는데 bucket은 MemberOnlyHash 클래스가 오버라이딩 한 것을 어떻게 알고 찾아가는지 이해가 되지 않습니다.
-
미해결모두를 위한 대규모 언어 모델 LLM Part 3 - 구글 제미나이(Google Gemini) API, OpenAI API와 젬마(Gemma)로 AI 어플리케이션 만들기
[긴급 최종질문수정16:47] 지금 이런 에러가 계속해서 연달아 나고 있는데 진행이 아예 안 됩니다
해결됐어요
-
미해결스프링부트 시큐리티 & JWT 강의
25강 마지막 테스트에서 오류
-25강 마지막 테스트 부분에서 실행 오류가 발생합니다.PrincipalDetailsService's loadUserByUsername()도 실행이 확인이 안됩니다. java.lang.NullPointerException: Cannot invoke "org.springframework.security.authentication.AuthenticationManager.authenticate(org.springframework.security.core.Authentication)" because "this.authenticationManager" is null at com.oopsw.myboot.config.jwt.JwtAuthenticationFilter.attemptAuthentication(JwtAuthenticationFilter.java:63) ~[classes/:na] 전체 코드는 다음과 같습니다.@RequiredArgsConstructor //4.1 public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter{ private final AuthenticationManager authenticationManager; //4.1 @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { try { ObjectMapper om=new ObjectMapper(); Users user=om.readValue(request.getInputStream(), Users.class); System.out.println(user); UsernamePasswordAuthenticationToken authenticationToken =new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword()); Authentication authentication =authenticationManager.authenticate(authenticationToken); PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal(); System.out.println(principalDetails.getUser().getUsername()); return authentication; } catch (IOException e) { e.printStackTrace(); } return null; } }
-
해결됨스프링 DB 1편 - 데이터 접근 핵심 원리
전체 구조
안녕하세요! 먼저 항상 친절한 답변 감사드립니다 ㅎㅎ구조가 어떻게 되어있는 건지 헷갈려서 나름 그려봤는데...JPA를 사용할 때 전체 db 연결 구조가 이렇게 되어있는게 맞을까요??
-
해결됨[퇴근후딴짓] 빅데이터 분석기사 실기 (작업형1,2,3)
'행'과 '인덱스'는 같은 개념이라고 봐도 될까요?
loc , iloc를 따질 때 '행'과 '인덱스'를 같은 개념이라고 생각하고 풀어도 상관없을까요..?
-
미해결김영한의 실전 자바 - 중급 1편
자바 중급2편까지 듣고 스프링강의으로 넘어가도 될까요??
예전에 기본편까지 듣고 스프링강의 들으러갔다가 쓴맛을 본 사람입니다아직 고급편이 나오지않았는데중급2편까지 듣고 스프링강의로 넘어가도 무방할까요?!
-
해결됨김영한의 실전 자바 - 중급 2편
섹션 7. 직접 구현하는 Set3
여기에서 hashCode의 값이 선생님과 다르게 출력되는데 잘못된 게 맞나요?문자 고유의 값이니까 같은 문자라면 어느 컴퓨터나 같은 hashCode가 출력되야 하는 게 맞는거죠??public class MyHashSetV2Main2 { public static void main(String[] args) { Member hi = new Member("hi"); Member jpa = new Member("JPA"); // 대문자 주의! Member java = new Member("java"); Member spring = new Member("spring"); System.out.println("hi.hashCode() = " + hi.hashCode()); System.out.println("jpa.hashCode() = " + jpa.hashCode()); System.out.println("java.hashCode() = " + java.hashCode()); System.out.println("spring.hashCode() = " + spring.hashCode()); MyHashSetV2 set = new MyHashSetV2(10); set.add(hi); // Member 타입의 인스턴스를 myHashSetV2에 넣음. set.add(jpa); set.add(java); set.add(spring); System.out.println("set = " + set); //검색 Member searchValue = new Member("JPA"); boolean result = set.contains(searchValue); System.out.println("hi.contains(" + searchValue + ") = " + result); } //출력 결과 hi.hashCode() = 3329 jpa.hashCode() = 73659 java.hashCode() = 3254818 spring.hashCode() = -895679987
-
미해결김영한의 실전 자바 - 중급 2편
제네릭 연습문제 2번
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.기본생성자를 생성안하니까 오류가 뜨는데 강사님 강의에는 기본생성자를 생성안해도 오류가 안뜨더라구요 toString이 역할을 대신한건가요? 1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요.
-
미해결스프링 부트 - 핵심 원리와 활용
섹션 8. 엑츄에이터 - http 요청 응답 관련 질문
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]안녕하세요.엑츄에이터 Http 요청 응답 관련 부분에서 강의 마지막 부분에이 기능은 매우 단순하고 기능에 제한이 많기 때문에 개발 단계에서만 사용하고, 실제 운영 서비스에서는 모니터 링 툴이나 핀포인트, Zipkin 같은 다른 기술을 사용하는 것이 좋다.라고 하셨는데 이 말씀은 운영 서비스에 직접 http 요청으로 조회하기보다는 모니터링 툴로 연동해서 모니터링 하는것을 권장한다는 말씀이실까요?
-
미해결설계독학맛비's 실전 Verilog HDL Season 2 (AMBA AXI4 완전정복)
34장 7분 50초 stream design role 관련 질문입니다
=================현업자인지라 업무때문에 답변이 늦을 수 있습니다. (길어도 만 3일 안에는 꼭 답변드리려고 노력중입니다 ㅠㅠ)강의에서 다룬 내용들의 질문들을 부탁드립니다!! (설치과정, 강의내용을 듣고 이해가 안되었던 부분들, 강의의 오류 등등)이런 질문은 부담스러워요.. (답변거부해도 양해 부탁드려요)개인 과제, 강의에서 다루지 않은 내용들의 궁금증 해소, 영상과 다른 접근방법 후 디버깅 요청, 고민 상담 등..글쓰기 에티튜드를 지켜주세요 (저 포함, 다른 수강생 분들이 함께보는 공간입니다.)서로 예의를 지키며 존중하는 문화를 만들어가요.질문글을 보고 내용을 이해할 수 있도록 남겨주시면 답변에 큰 도움이 될 것 같아요. (상세히 작성하면 더 좋아요! )먼저 유사한 질문이 있었는지 검색해보세요.잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.==================7분 50초쯤 우 상단의 타이밍도에서 SOF 시점에 첫번째 핸드쉐이크가 일어나는데 이전 강의의 stream design role 2번에 의해 핸드쉐이크가 일어나기 이전에 먼저 1로 뜬 신호(이 경우는 ready가 먼저 뜸)는 핸드쉐이크 전까지 1이 그대로 유지되어야 하는데 0으로 떨어지는 경우가 발생합니다. 이것은 왜이렇게 되는건가요?그리고 핸드쉐이크 시점 근처에서만 1로 유지되면 되는거 아닌가요? design role 2번에 대해서 조금 더 자세히 설명해주시며 정말 감사하겠습니다!
-
미해결Next + React Query로 SNS 서비스 만들기
로그인후 바로 뒤로가기, 회원가입 후 홈으로 이동하고 session에 정보 안쌓임
안녕하세요 선생님.로그인 후에 새로고침이나 url을 치고 /(메인)으로 가면 홈으로 잘 리다이렉트 되는데 로그인 후 바로 뒤로가기를 누르면 리다이렉트되지 않고 / 페이지로 이동합니다. 이 부분 어떻게 하면 좋을지 문의 드립니다. 회원가입 후303뜨면서 홈으로 이동하는데, 이 303이 괜찮은건지와이동 후에 로그아웃버튼에서 session 정보를 가져오지 못하고 있습니다. 새로고침하면 잘 나옵니다. me정보를 가져올때 useEffect로 바꿔야할지 문의 드립니다.로그를 보면 회원가입 후, 로그인도 잘 되는것 같은데 어떤부분을 확인해야할지 알려주시면 감사하겠습니다. @/app/(beforelogin)/_lib/signup.tsx'use server'; import { signIn } from '@/auth'; import { redirect } from 'next/navigation'; const onSubmit = async (prevState: any, formData: FormData) => { if (!formData.get('id') || !(formData.get('id') as string).trim()) { return { message: 'no_id' }; } if (!formData.get('name') || !(formData.get('name') as string).trim()) { return { message: 'no_name' }; } if (!formData.get('password') || !(formData.get('password') as string).trim()) { return { message: 'no_password' }; } if (!formData.get('image')) { return { message: 'no_image' }; } let shouldRedirect = false; try { console.log('-------------------------signup start'); const response = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/users`, { method: 'post', body: formData, credentials: 'include', // cookie 전달 위해서 }); // console.log(response); console.log(response.status); if (response.status === 403) { return { message: 'user_exists' }; } const user = await response.json(); console.log(user, '-------------------------signup'); shouldRedirect = true; // 회원가입 성공하고 로그인 시도 await signIn("credentials", { username: formData.get('id'), password: formData.get('password'), redirect: false, }) } catch (error) { console.error(error); return { message: null }; } if (shouldRedirect) { redirect('/home'); // redirect는 try/catch문에서 쓰면 안된다. } } export default onSubmit; @/auth.tsimport NextAuth from "next-auth" // import CredentialsProvider from "next-auth/providers/credentials" import Credentials from "next-auth/providers/credentials" export const { // api 라우트 handlers: { GET, POST }, // auth 함수 실행하면 로그인 유무알 수 있다. auth, // 로그인 하는 함수 signIn } = NextAuth({ pages: { signIn: "/i/flow/login", newUser: '/i/flow/signup', }, providers: [ Credentials({ // You can specify which fields should be submitted, by adding keys to the `credentials` object. // e.g. domain, username, password, 2FA token, etc. credentials: { id: {}, password: {}, }, authorize: async (credentials) => { console.log('-------------------------------------------auth.ts'); const authResponse = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(credentials) }) // console.log('authResponse-----------------------------------', authResponse); // 로그인 실패 if (!authResponse.ok) { return null } // 로그인 성공 const user = await authResponse.json(); console.log('user', user); // return user object with the their profile data return { ...user, name: user.nickname } }, }), ] }) @/app/(beforelogin)/_component/loginmodal.tsx'use client'; import style from '@/app/(beforeLogin)/_component/login.module.scss'; import { useRouter } from 'next/navigation'; import { SubmitHandler, useForm } from 'react-hook-form'; // import { signIn } from '@/auth'; // 서버환경일 때 import { signIn } from 'next-auth/react'; // 클라이언트일 때 type formProps = { id: string, password: string, } export default function LoginModal() { const { register, handleSubmit, formState: { errors } } = useForm<formProps>(); const router = useRouter(); const onClickClose = () => { router.back(); // TODO: 뒤로가기가 /home이 아니면 /home으로 보내기 }; const onSubmit: SubmitHandler<formProps> = async (data: formProps) => { console.log(data); try { await signIn('credentials', { ...data, redirect: false }); router.replace('/home'); } catch(error) { console.error(error); console.log('아이디와 비밀번호가 일치히자 않습니다.'); } }; return ( <div className={style.modalBackground}> <div className={style.modal}> <div className={style.modalHeader}> <button className={style.closeButton} onClick={onClickClose}> <svg width={24} viewBox='0 0 24 24' aria-hidden='true' className='r-18jsvk2 r-4qtqp9 r-yyyyoo r-z80fyv r-dnmrzs r-bnwqim r-1plcrui r-lrvibr r-19wmn03'> <g> <path d='M10.59 12L4.54 5.96l1.42-1.42L12 10.59l6.04-6.05 1.42 1.42L13.41 12l6.05 6.04-1.42 1.42L12 13.41l-6.04 6.05-1.42-1.42L10.59 12z'></path> </g> </svg> </button> <div>로그인하세요.</div> </div> <form onSubmit={handleSubmit(onSubmit)}> <div className={style.modalBody}> <div className={style.inputDiv}> <label className={style.inputLabel} htmlFor='id'> 아이디 </label> <input id='id' className={style.input} type='text' placeholder='' {...register('id', { required: '아이디를 입력해주세요.' })} /> {errors.id?.message && typeof errors.id.message === 'string' && <p>{errors.id.message}</p>} </div> <div className={style.inputDiv}> <label className={style.inputLabel} htmlFor='password'> 비밀번호 </label> <input id='password' className={style.input} type='password' placeholder='' {...register('password', { required: '비밀번호를 입력해주세요.' })} /> {errors.password?.message && typeof errors.password.message === 'string' && <p>{errors.password.message}</p>} </div> </div> <div className={style.modalFooter}> <button className={style.actionButton}>로그인하기</button> </div> </form> </div> </div> ); } @/app/(beforelogin)/page.tsximport Main from '@/app/(beforeLogin)/_component/Main'; import { auth } from '@/auth'; import { redirect } from 'next/navigation'; export default async function Home() { console.log('--------------before login home'); const session = await auth(); if (session?.user) { redirect('/home'); return null; } return ( <> <Main /> </> ); }
-
미해결Arm 아키텍처: 메모리 모델과 배리어 [저자직강 3부-3]
메모리 맵드 I/O에 대해서
안녕하세요 강의를 정말 잘 듣고 있습니다!!메모리 맵드 I/O에 대해 궁금한게 있어서 질문을 남깁니다.강의 내용 중 메모리 맵드 I/O 된 영역은 device memory라고 말씀을 하시면서 메모리 맵드 I/O가 된 경우 ldr str와 같은 명령어에 의해 그 영역에 값을쓰면 그와 연결된 포트를 통해 I/O장치 또는 레지스터에 값이 쓰여진다라고 말씀을 하셨는데요, 그러면 mcr mrc msr mrs와 같은 명령어를 통해 레지스터에 값을 써야 하는 것들은 메모리 맵드 I/O가 아닌건가요? 메모리 맵드 I/O된 것들은 전부 ldr str과 같은 명령어를 사용하여 값을 읽고 쓸 수 있는건가요??? 추가로 궁금한것이, 제가 잘못 알고있는것일 수도 있지만, 임베디드 레시피라는 책에 보면 메모리 맵드 I/O 같은 경우 Register 크기 만큼씩 Access 가능하다고 나와있습니다. 그렇다면 memory mapped I/O된 영역에 레지스터 크기가 4바이트인데 strb 또는 strh와 같은 명령어를 통해 read를 하면 에러가 난다고 이해하면 될까요??? 만약에 strb strh와 같은 명령어를 통해 에러가 발생한다면 그때 발생하건 exception인가요 아니면 그냥 ignore 되는건가요???
-
미해결[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!
다시 getDetail호출?
제 생각이 조금이라도 이상한 곳이 있다면 말씀해주세요 ~! ㅎㅎ첫번째 질문은 , detail_screen.dart에서initState에 ref.read(restaurantProvider.notifier).getDetail(id: widget.id); 만 사용하였는데만약 restaurantDetailModel이 이미 있는 id를 또 getDetail한 거였다면, 다시 getDatil을 호출할 필요가 없으므로이떄 initState에 ref.read(restaurantDetailProvider) is restaurantDetailModel 라면 getDatil을 호출하지 않겠다를추가로 넣으면 좋겠다 생각하는데 제 생각이 어떠한가요?? 두번째 질문은 restaurant > provider > restaurant_provider.dart 에서 네트워크 요청을 하다가 등등 에러가 날수 있을 거 같은데 여기는 catch 로 잡아서 state를 왜 error로 만들지 않았나 궁금합니다..!
-
해결됨파이썬 알고리즘 트레이딩 파트2: Interactive Brokers API를 활용한 실시간 알고리즘 트레이딩
IBKR Desktop Global Configuration 설정
안녕하세요 강사님 IBKR Desktop 다운로드 이후 api 설정을 해주려고 했는데요 뭔가 버전이 다른 건지 화면이 달라서 어디서 설정을 할 수 있는지가 잘 안보여서 문의드립니다!감사합니다!
-
미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
@OneToMany 지연 로딩 관련하여 질문 드립니다.
[질문 내용]안녕하세요! @OneToMany지연로딩 관련해서 질문 드립니다.아래는 Team, Member 엔티티로, 연관관계를 갖습니다. (1:N) team 엔티티// Team.java package hellojpa; import jakarta.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; @OneToMany(mappedBy = "team", fetch = FetchType.LAZY) 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; } } member.class , 엔티티// Member.java package hellojpa; import jakarta.persistence.*; import javax.xml.namespace.QName; import java.util.Date; @Entity public class Member { @Id @GeneratedValue @Column(name = "MEMBER_ID") private Long id; @Column(name = "USERNAME") private String username; @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; } } 위의 team ,member에서는 @OneToMany인데, 아래 코드 작동 시, 프록시 객체들이 조회안되고 진짜 엔티티가 조회되어 지연로딩이 발생 안합니다. package hellojpa; import jakarta.persistence.*; import java.util.List; public class JpaMain { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); EntityManager em = emf.createEntityManager(); //code EntityTransaction tx = em.getTransaction(); tx.begin(); try{ //저장 Team team = new Team(); team.setName("TeamA"); em.persist(team); Member member1 = new Member(); Member member2 = new Member(); member1.setUsername("member1"); member1.setTeam(team); member2.setUsername("member2"); member2.setTeam(team); em.persist(member1); em.persist(member2); em.flush(); em.clear(); Team findTeam = em.find(Team.class, team.getId()); List<Member> members = findTeam.getMembers(); // 이 부분에서 프록시 객체로 조회가 되지 않습니다.! for (Member m : members) { System.out.println(m.getClass()); // member.class로 콘솔 출력 됩니다.. System.out.println(m.getUsername()); } tx.commit(); } catch (Exception e){ tx.rollback(); } finally { em.close(); } emf.close(); } } 아래는 위의 코드 실행 시 콘솔 창입니다. Hibernate: create sequence Member_SEQ start with 1 increment by 50 Hibernate: create sequence Team_SEQ start with 1 increment by 50 Hibernate: create table Member ( MEMBER_ID bigint not null, TEAM_ID bigint, USERNAME varchar(255), primary key (MEMBER_ID) ) 5월 15, 2024 12:26:48 오후 org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@1fbf088b] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode. Hibernate: create table Team ( TEAM_ID bigint not null, name varchar(255), primary key (TEAM_ID) ) Hibernate: alter table if exists Member add constraint FKl7wsny760hjy6x19kqnduasbm foreign key (TEAM_ID) references Team Hibernate: select next value for Team_SEQ Hibernate: select next value for Member_SEQ Hibernate: select next value for Member_SEQ Hibernate: /* insert for hellojpa.Team */insert into Team (name, TEAM_ID) values (?, ?) Hibernate: /* insert for hellojpa.Member */insert into Member (TEAM_ID, USERNAME, MEMBER_ID) values (?, ?, ?) Hibernate: /* insert for hellojpa.Member */insert into Member (TEAM_ID, USERNAME, MEMBER_ID) values (?, ?, ?) ///////////////// ///////////////// ///////////////// Hibernate: select t1_0.TEAM_ID, t1_0.name from Team t1_0 where t1_0.TEAM_ID=? Hibernate: select m1_0.TEAM_ID, m1_0.MEMBER_ID, m1_0.USERNAME from Member m1_0 where m1_0.TEAM_ID=? // 실제 객체 class hellojpa.Member member1 class hellojpa.Member member2 for-each로 member 클래스를 출력했을 때, 프록시 객체로 조회가 되지 않으며, team.getMembers()를 실행할 때 in절로 여러개의 members엔티티를 조회해 오는 것 같습니다.. 제가 강의를 통해 이해한 바로는, @OneToMany는 기본적으로 지연로딩이 걸려 있어, 컬렉션을 조회할 때 각 엔티티들은 '프록시'로 조회되고(지연로딩) , 각 컬렉션의 객체들에 접근할 때 추가적인 (select 문) 조회 쿼리가 발생하여 N+1문제를 낳는다고 알고 있습니다.. -아래는 후반부의 강의 코드 - 강의상 지연이 발생 하는 코드 => OrderItemDto에서 N+1쿼리 발생package jpabook.jpashop.api; import jpabook.jpashop.domain.Address; import jpabook.jpashop.domain.Order; import jpabook.jpashop.domain.OrderItem; import jpabook.jpashop.domain.OrderStatus; import jpabook.jpashop.repository.OrderRepository; import jpabook.jpashop.repository.OrderSearch; import lombok.Data; import lombok.Getter; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.time.LocalDateTime; import java.util.List; import java.util.stream.Collectors; @RestController @RequiredArgsConstructor public class OrderApiController { private final OrderRepository orderRepository; @GetMapping("/api/v1/orders") public List<Order> ordersV1() { List<Order> all = orderRepository.findAllByString(new OrderSearch()); for (Order order : all) { order.getMember().getName(); //Lazy 강제 초기화 order.getDelivery().getAddress(); //Lazy 강제 초기환 List<OrderItem> orderItems = order.getOrderItems(); orderItems.stream().forEach(o -> o.getItem().getName()); //Lazy 강제 } return all; } @GetMapping("/api/v2/orders") public List<OrderDto> ordersV2(){ List<Order> orders = orderRepository.findAllByString(new OrderSearch()); List<OrderDto> collect = orders.stream() .map(o -> new OrderDto(o)) .collect(Collectors.toList()); return collect; } @Data static class OrderDto{ private Long orderId; private String name; private LocalDateTime orderDate; private OrderStatus orderStatus; private Address address; private List<OrdereItemDto> orderItems; public OrderDto(Order o) { orderId = o.getId(); name=o.getMember().getName(); orderDate=o.getOrderDate(); orderStatus=o.getStatus(); address=o.getDelivery().getAddress(); orderItems = o.getOrderItems().stream() .map(orderItem -> new OrdereItemDto(orderItem)) .collect(Collectors.toList()); } } @Getter static class OrdereItemDto{ private String itemName; //상품명 private int orderPrice; //주문 가격 private int count; //주문 수량 public OrdereItemDto(OrderItem orderItem) { itemName=orderItem.getItem().getName(); //문제 상황, 지연로딩 발생 orderPrice=orderItem.getItem().getPrice(); count = orderItem.getCount(); } } } - Order, OrderItems에서도 @OneToMany인데, 지연로딩이 발생하여, orderItems 각각의 필드값을 조회시 N+1쿼리가 나가는 것이 확인되어, 차이점이 무엇인지 알고 싶습니다.@GetMapping("/api/v1/orders") public List<Order> ordersV1() { List<Order> orders = orderRepository.findAllByString(new OrderSearch()); // 지연로딩 데이터 가져오기 for (Order order : orders) { order.getMember().getName(); // 지연로딩 초기화 order.getDelivery().getAddress(); // 지연로딩 초기화 // 2. orderItem -> getClass() for(OrderItem o : orderItems) { System.out.println(o.getClass()) //프록시객체 } //3. 여기서는 select 나가서 진짜 엔티티 갖고 오는거 orderItems.stream().forEach(orderItem -> orderItem.getItem().getName()); // 상품명을 가져오기 위해서 지연로딩 강제 초기화 } return orders; }} 추가질문.. @OneToMany를 걸 경우, 기본 전략이 lazyLoading으로 알고 있습니다..이런 상황에서 getEntityList를 할 때, 프록시 객체가 아니라, 왜 한꺼번에 엔티티를 들고오는지 궁굼합니다..!