묻고 답해요
130만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨토비의 스프링 부트 - 이해와 원리
섹션 9 세번째 강의 문의
안녕하세요. 강의 정말 잘 보고 있습니다. 다름이 아니라 섹션9 세번째 강의 jdbc transaction manager 설정 및 테스트 하는 과정에서 마지막 부분에 첫번째 테스트는 통과 하지만 두번째 테스트는 실패합니다라고 설명 해주셨는데요, 아래 실제 콘솔을 보면 두번째 테스트가 성공 하고 첫번째 테스트가 실패 하고 있습니다. 그래서 궁금한 점은 junit에서 각 테스트는 코드상에서 위아래와 무관 하게 각 테스트 메서드가 병렬적으로 동작 하고, 그 과정에서 먼저 디비를 터치하고 트랜잭션을 완료 한 테스트가 먼저 성공 하는 것 인지 궁금 합니다.
-
미해결스프링 DB 1편 - 데이터 접근 핵심 원리
예외처리
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]강의에서 예외를 직접 잡을 일이 별로 없다고 말씀해주셨는데, 예를 들어 회원가입을 할 때 중복된 아이디를 입력해서 오류가 발생해서 오류 메시지를 보여줘야 하는 경우는 개발자가 잡아야 하는 예외라고 봐도 될까요?
-
해결됨스프링 DB 1편 - 데이터 접근 핵심 원리
왜 계속 커넥션 풀 내 새로운 커넥션을 사용하는 건가요?
트랜잭션 매니져 사용하는 service 테스트 하는 MemberServiceV3_1Test 실행시키면 나오는 로그입니다. 제가 이해가 안가는 것은find by id , save, delete 같은 repository 함수들은 항상 close를 마지막으로 끝내잖아요?그럼 항상 커넥션 하나 사용한 다음에 다시 pool에 반환되니, 매번 conn0만 사용해야하는거 아닌가요? 그리고 지금 여러명이 DB에 들락거리는 것도 아니고 저 혼자만 테스트해보는건데왜 한개의 커넥션이 아닌 여러개의 커넥션을 사용하게 되는 건가요? 커넥션 풀에 있는 다른 커넥션을 사용해야한다는 것은 특정 커넥션들이 트랜잭션 상태에 있기 때문에어쩔 수 없이 풀에 남아있는 커넥션을 사용해야하는거잖아요?근데 저 혼자만 테스트하면 매번 DB작업한 다음에 커넥션을 다시 커넥션풀에 갖다 놓을텐데(모든 repository 함수들이 close로 끝나기 때문에) 왜 conn0이 아닌 5 6 7번까지 사용하게 되는걸까요??
-
해결됨스프링 DB 1편 - 데이터 접근 핵심 원리
DriverManagerDataSource 질문
이 DriverManagerDataSource가 커넥션 풀은 아닌거죠? 매번 getConnection할때마다 새 커넥션을 생성하긴 하지만URL USERNAME PASSWORD 를 매번 전달하지는 않아도 되는그냥 좀 더 편리한 DriverManager 라고 생각하면 되는 걸까요
-
미해결스프링 DB 1편 - 데이터 접근 핵심 원리
빈 등록
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]기본적인건데 애매해서 질문드립니다. test코드에서 RepositoryV3와 ServiceV3_3를 @Bean으로 등록하지 말고 실제 RepositoryV3클래스와 ServiceV3_3클래스에 @RequiredArgsConstructor와 각각 @Repository, @Service를 추가해서 빈으로 등록을 해도 똑같이 내부에서 작동하는 것으로 봐도 괜찮을까요? test를 실행했을 때 오류가 발생하지 않아서 질문드립니다.
-
미해결스프링 DB 1편 - 데이터 접근 핵심 원리
테스트코드에서 transactionManager() 사용이유
안녕하세요@Bean PlatformTransactionManager transactionManager(){ return new DataSourceTransactionManager(dataSource()); }테스트코드에서 이 로직을 제거해도 작동이 잘 되는데요MemberServiceV3_3 클래스 에서@Transactional 을 사용해서트랜잭션 설정하는 로직이 필요없을것 같았는데위 코드를 사용하신 이유가있으실까요?
-
해결됨스프링 DB 1편 - 데이터 접근 핵심 원리
h2 데이터베이스 관련
안녕하세요 h2 데이터베이스에 대한 질문이 있습니다. h2 데이터베이스는 "연결" 누르고 sql 실행할 수 있는 창에 들어왔다면 이게 데이터베이스 서버를 띄운건가요?그럼 이 데이터베이스 창을 닫으면 자동으로 데이터베이스 서버를 다운시킨건가요? 그러니까 종료시킨건가요?그럼 spring 실행을 시킬때 항상 이 h2 데이터베이스에 연결해서 접속한다음에 실행해야하는건가요?그리고 현재는 저 한명만이 h2로 테스트하는거니까 그냥 계속 Embedded mode로 접속해도 되는거죠?감사합니다.
-
해결됨토비의 스프링 부트 - 이해와 원리
@Conditional 학습테스트 << 강의중 질문있습니다!
안녕하세요 토비님. 수업 잘 듣고있습니다다름이 아니라,학습테스트 강의 중에, @Conditional() 괄호 안에 있는 클래스의 리턴값에 따라 true/false를 반환하는 void conditional() 테스트 메서드에 대해 질문이 있습니다. true를 리턴하는 경우 코드가AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();ac.register(Config1.class);ac.refresh();MyBean bean = ac.getBean(MyBean.class);이고, false를 리턴하는 경우는AnnotationConfigApplicationContext ac2 = new AnnotationConfigApplicationContext();ac2.register(Config2.class);ac2.refresh();MyBean bean2 = ac2.getBean(MyBean.class);인데요..여기서 true 테스트는 성공하고 false테스트는 실패를 합니다.여기서 생긴 의문점은, ac와 ac2 둘다 스프링 컨테이너를 가리키는 것인데, ac.getBean의 결과와 ac2.getBean의 결과가 다르다는것은 앞서 ac.register()해서 등록한 MyBean이 ac2 스프링 컨테이너에는 없다는 것으로 해석이 되는데요.. 스프링에서는 스프링 컨테이너라는것이 하나 존재하고 그 안에 여러 빈들이 들어있다고 지금까지 생각하고 있었습니다.그래서 ac에서 bean을 등록했기때문에 ac2.getBean을 해도 똑같이 MyBean이 존재해야 하는것이 아닌가?? 라는 의문점이 듭니다. Q1. ac와 ac2 는 다른 스프링 컨테이너인가요 ??Q2.다른것이라면 , 스프링에서는 스프링컨테이너가 여러개 존재하는 것인가요??읽어주셔서 감사합니다. 새해 복 많이 받으세요
-
미해결스프링 DB 1편 - 데이터 접근 핵심 원리
강의자료 관련
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]안녕하세요 강의 잘 듣고 있습니다. pdf 강의자료 6.스프링과 문제 해결 pg.11의 MemberServiceV4Test 코드에서 @AfterEach의 after 메소드에 붙은 throws SQLException를 제거해도 될 것 같아서 글을 남깁니다. 좋은 하루 되세요.
-
해결됨토비의 스프링 부트 - 이해와 원리
안녕하세요 토비님. 강의중 질문있습니다.
안녕하세요 강의 잘 듣고있는 학생입니다.다름이 아니라 applicationContext의 생성과정이 아직 스스로 정리가 되어있지 않아 이렇게 질문을 드립니다..우선 제 생각은 이렇습니다.applicationContext를 생성하면서 내부적으로 onRefresh() 를 오버라이딩을 합니다.여기서 ServletWebServerFactory serverFactory = this.getBean(ServletWebServerFactory.class); DispatcherServlet dispatcherServlet = this.getBean(DispatcherServlet.class); 을 통해서 등록된 Bean을 들고오게 됩니다.여기서 드는 의문점1은, this.getBean(DispatcherServlet.class)을 한다는 것은 이미 DispatcherServlet이 Bean등록이 되어있다는 것이고 그렇다면 applicationContext라는 변수를 만들기 전에 이미 Bean이 등록이 되어있었다고 생각됩니다. 그러면 applicationContext라는 변수를 방금 막 선언하고 아직 객체를 할당하는 과정인데 this.getBean이 작동한다?this는 분명 applicationContext인데 어떻게 applicationContext안의 getBean을 통해 dispatcherServlet등이 불러와지는지 모르겠습니다.. (요약하면, 아직 인스턴스를 만들지 않았는데 어떻게 applicationContext안의 getBean이 동작할 수 있는가? 입니다) 두번째는, 어떻게든 위의 과정을 거쳐서 applicationContext(스프링 컨테이너)가 서블릿 컨테이너와 연결이 되었습니다. 이후 applicationContext.register(HellobootApplication.class)를 하게되는데, 이미 위에서 빈 등록도 다 하고 모든걸 가지고 있는것 같은데 왜 register가 필요한것인지 모르겠습니다 ㅠㅠ register하는 코드는HellobootApplication.class라는 클래스 구성정보를 읽어서 그 내용을 토대로 빈(이때 이 빈은 HellobootApplication 빈 일까요??)을 등록한다 라고 생각되는데, HellobootApplication 클래스의 정보에는 팩토리 메서드 2개(ServletWebServerFactory,DispatcherServlet) 와 applicationContext를 구성하는 코드밖에 없다고 생각됩니다. applicationContext를 구성하는 과정에서 이미 팩토리 메서드 정보를 사용한 것 같은데, 그렇다면 이미 빈을 만드는데 필요한 정보는 다 가지고 있는것이 아닌가? 라고 생각이 듭니다. 이런 부분들이 자꾸 맘에 걸려서 다음강의로 못넘어가겠습니다 ㅠㅠ 명확하게 정리해주시면 감사하겠습니다..
-
미해결스프링 DB 1편 - 데이터 접근 핵심 원리
Controller 안에서 @Transaction 설정이 다른 2개의 method 호출
@Slf4j @RestController public class AController { @Autowired AService aService; @Autowired BService bService; @PostMapping("/api/v2/aaaa") public ResponseEntity<ResponseDto> postA( @RequestBody @Valid PostADto postADto, HttpServletRequest request) throws Exception { A a = aService.getA(request); HashMap<String, Object> result = bService.createB(postADto, a); .... }위 와 같이 컨트롤러에서 aService.getA(request); 와 bService.createB(postADto, user); 메서드를 호출합니다.각 메서드는 아래와 같이 선언돼있습니다.@Transactional(readOnly = true) public A getA(HttpServletRequest request) { .... return aRepository.findById(id).orElse(null); }@Transactional public HashMap<String, Object> createB(PostADto postADto, A a) { ...... bRepository.save(postADto.toB()); ...... return ...; }getA 메서드안에서 TransactionSynchronizationManager.isCurrentTransactionReadOnly(); log 출력했을때 readonly = true로 나오고 readDB로 잘 연결됩니다. 하지만 createB 메서드안에서 TransactionSynchronizationManager.isCurrentTransactionReadOnly(); log 출력했을때 readonly = false로 나오는데 실제로는 readDB로 연결되고 query를 발생시켜 아래와 같은 오류가 발생합니다.Caused by: java.sql.SQLException: The MySQL server is running with the --read-only option so it cannot execute this statement at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:129) at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97) Caused by: java.sql.SQLException: The MySQL server is running with the --read-only option so it cannot execute this statement 컨트롤러에 @transactional 을 선언하지 않았기 때문에 각 메서드에서 트랜잭션이 수행되어 getA 메서드에서는 readDB로 createB 메서드에서는 writeDB로 요청이 된다고 알고 있었는데 그런 방식으로 동작이 안되 혼란스럽습니다. 어떤 이유로 이런 문제가 발생하는지 궁금합니다. 그리고 왜 이렇게 동작하는지 어느 부분을 학습하면 좋은지 궁금합니다.
-
미해결스프링 DB 1편 - 데이터 접근 핵심 원리
@Transactional 내부에서 트랜젝션 템플릿이 사용되나요
@Transactional 내부에서도 결국 트랜젝션 템플릿을 사용해서 트랜젝션 처리를 하는지 궁금합니다!
-
미해결스프링 DB 1편 - 데이터 접근 핵심 원리
14:18에서 AopCheck() 테스트하는 부분 질문드립니다
@Test void AopCheck() { log.info("memberService.class={}", memberService.getClass()); log.info("memberRepository.class={}", memberRepository.getClass()); }테스트를 실행하면 memberService.getClass()에 해당하는 부분만 CGLIB~~이 적용된, 즉 AOP가 적용된 인스턴스라는 것을 확인할 수 있었습니다. memberRepository.getClass()는 평범한 인스턴스이고 memberService.getClass()만 AOP가 적용된 인스턴스인 이유는 추측건대 @Transactional // proxy가 비즈니스 로직 대신 호출. 성공하면 commit, 런타임 예외가 터지면 rollback public void accountTransfer(String fromId, String toId, int money) throws SQLException { bizLogic(fromId, toId, money); }MemberService내의 메서드에 @Transactional이 붙어서인 것 같습니다. 클래스 레벨에 @Transactional을 붙이지도 않았는데도 클래스 정보를 가져오는 메서드인 getClass()를 통해 AOP가 적용된 인스턴스로 확인되는 이유가 궁금합니다.
-
미해결토비의 스프링 부트 - 이해와 원리
registerBean과 어셈블러(스프링 컨테이너)의 싱글톤 인스턴스 생성
안녕하세요런타임시 스프링컨테이너(어셈블러)가 컨트롤러의 구현체(ex SimpleHelloService, ComplexHelloService)를 컨트롤러에 주입해줘야한다는 것을 알고있습니다.이때 스프링 컨테이너는 클래스의 싱글톤 객체를 생성하여 주입하는 것으로 학습했습니다. 강의처럼 SimpleHelloService 클래스 만을 빈으로 등록하고 생성한다면, ComplexHelloService가 등장시 1. ComplexHelloService를 빈으로 등록하는 지 2. 싱글톤 객체의 구현체를 어떻게 선택하고 생성하는지 알고싶습니다. 감사합니다.
-
미해결스프링 DB 1편 - 데이터 접근 핵심 원리
강의 4:50에서 커넥션 풀 고려하는 부분 질문드립니다
리소스 정리에 관련해서 질문드립니다. con.close()의 경우, 커넥션 풀을 사용하는 커넥션일 때 close()시에 커넥션 종료가 아닌 커넥션 풀로 다시 반환된다는 것으로 이해했습니다. 그런데 con.setAutoCommit(true)로 되돌릴 때 커넥션 풀을 고려해야한다는 부분이 이해가 가지 않아서 질문드립니다. 커넥션 풀과 상관없이 오토커밋은 true로 바꿔야하는 것 아닌가 해서요. +추가 질문: 개발자가 트랜젝션 매니저를 이용한 트랜젝션을 구현한다면 따로 위의 두가지 코드를 작성해줄 필요가 없는 것 맞는가해서 질문드립니다.(ServiceV2에서의 finally 구문을 ServiceV3_1에서는 생략한 것과 같은 맥락으로) 친절한 답변 항상 감사드립니다
-
미해결스프링 DB 1편 - 데이터 접근 핵심 원리
AopCheck() 로그가 강의와 다릅니다
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. memberService 부분의 로그가강의에 나온 'EnhancerBySpringCGLIB..'부분으로 나오지않고 SpringCGLIB로만 나옵니다. 오류가 나지는 않는데 강의와 동일하게 적용이 되고 있는지 궁금합니다.
-
미해결스프링 DB 1편 - 데이터 접근 핵심 원리
리소스 동기화 == 트랜젝션 동기화 인가요?
트랜젝션 매니저 설명해주시는 부분의 PDF 내용을 보다보니 리소스 동기화와 트랜젝션 동기화라는 용어가 같은 내용(같은 트랜젝션 내에서 커넥션을 동일하게 유지)을 지칭하는 것 같아서 질문드립니다.
-
미해결스프링 DB 1편 - 데이터 접근 핵심 원리
DELETE문 테스트 하는 부분 질문드립니다.
항상 강의 잘 듣고 있습니다 🙂다름이 아니라 이번 강의에서는 이전에 배웠던 assertThrows를 사용하시지 않고 assertThatThrownBy를 사용하셨는데 이 둘은 결국 하는 일이 같은 것이 아닌가 해서 질문드립니다. 강사님께서 강의 중 작성하신 코드와 제가 작성한 기존의 assertThrows를 이용한 코드가 정확히 같은 것이 맞는가해서 질문드립니다.// 강사님 (assertThatThrownBy) assertThatThrownBy(() -> repository.findById(member.getMemberId())).isInstanceOf(NoSuchElementException.class); // AssertThrows (내 버전) assertThrows(NoSuchElementException.class, () -> repository.findById(member.getMemberId()));
-
해결됨스프링 DB 1편 - 데이터 접근 핵심 원리
SQLException 질문
Service코드가 JDBC에 의존적이라 스프링이 제공하는 PlatformTransactionManager 인터페이스에 의존하게 바꿨는데 그러면 SQLException 예외도 없어도 되나요 ?
-
미해결스프링 DB 1편 - 데이터 접근 핵심 원리
connection total 개수에 대한 질문
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. @Testvoid dataSourceConnectionPool() throws SQLException, InterruptedException {//커넥션 풀링 : 히카리 풀 사용 HikariDataSource dataSource = new HikariDataSource(); dataSource.setJdbcUrl(URL); dataSource.setUsername(USERNAME); dataSource.setPassword(PASSWORD); dataSource.setMaximumPoolSize(10); //pool사이즈 최대 지정 dataSource.setPoolName("MyPool"); //pool이름 설정 useDataSource(dataSource); Thread.sleep(1000); //pool에 추가하는 것까지 log로 확인하기 위해서 지연시간 추가} 다음과 같이 코드를 작성하였는데 My Pool의 개수가 강의에서와 다르게 설정됩니다.setMaximumPoolSize을 10으로 맞췄는데도 다른 이유가 무엇인가요? Thread.sleep(1000);을 1000 -> 10000으로 늘리니 활성화되는 커넥션이 늘어나던데 이 시간과 관련있는건가요?