묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결스프링 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으로 늘리니 활성화되는 커넥션이 늘어나던데 이 시간과 관련있는건가요?
-
해결됨스프링 DB 1편 - 데이터 접근 핵심 원리
Checked, Unchecked 예외 변환 질문드립니다.
안녕하세요. 복습 도중 개념적으로 혼동이 와서 질문드립니다.Checked Exception - 체크를 하라고 만든 예외Unchecked Exception(Runtime Exception) - 체크를 하지 말라고 만든 예외예를 들어서 NullPointerException 같은 경우, 개발자가 예외를 잡아서 처리하지 않습니다.런타임 예외는 원래 처리하지 않기 때문에 당연하다고 생각합니다.그런데 체크를 하라고 만든 예외를 체크를 하지 말라고 만든 예외로 변환을 하는 것이 개념적으로 이해가 잘 가지 않습니다.Checked 예외를 Unchecked 예외로 변환함으로써Unchecked는 체크를 하는게 아닌데, 마치 Checked 처럼 핸들링 하는 느낌이 듭니다.물론 강의에서 설명해 주신 변환을 함으로써의 이점은 이해가 잘 갑니다!throws SQLException → throws JPAException반복적인 throws 을 변경하지 않아도 되고, 특정 기술에 의존하지 않아도 됨다만, 이는 커스텀 Checked 예외를 사용해도 해결할 수 있다고 생각합니다.public class MyCustomCheckedException extends Exception { ... }Checked 예외를 커스텀 Checked 예외로 변환 이 경우에는 반복적인 throws 작성은 피할 수 없긴 합니다.코틀린 등의 언어에서 이런 개념적 혼동을 막기 위해 Checked/Unchecked를 나누지 않는 것인지..제가 무언가 잘못 이해하고 있는것이 있을까요?
-
미해결토비의 스프링 부트 - 이해와 원리
spring initializr에서 강의 버전과 달라요
강의에서는스프링부트 2.x버전이고 자바도 11이 있는데지금은 스프링부트도 3.x버전만있고자바도 21, 17만 있습니다 어떻게 해야되나요이후 강의에서 하는걸 따라하는거에 차질이 없으려면스프링부트와 자바 어떤 버전으로 해야하나요
-
해결됨스프링 DB 1편 - 데이터 접근 핵심 원리
트랜잭션 시작 및 종료 관련 질문 있습니다!
안녕하세요 강의 듣다가 제가 이해한 게 맞는지 확인 차 질문 드립니다!시작 : 서비스 계층에서 getTransaction()을 통해 트랜잭션을 시작하면 트랜잭션 매니저에서 커넥션을 생성하여 DB 트랜잭션을 시작한다.종료 : 서비스 계층에서 commit() 혹은 rollback()을 통해 트랜잭션을 종료하면 동기화 매니저에서 커넥션을 꺼내와 DB 트랜잭션을 커밋 혹은 롤백한다.라고 설명해 주셨는데, 여기서 트랜잭션 매니저의 getTransaction(), commit(), rollback()은 DB에 직접 영향을 미치지 않고, 커넥션을 트랜잭션 용으로 동기화 혹은 종료시키는 역할인가요? 그렇다면 실질적으로 DB 상에서 트랜잭션을 시작하고, 커밋이나 롤백을 수행하여 반영하는 로직은 DataSourceTransactionManager 내부에 있나요?
-
미해결스프링 DB 1편 - 데이터 접근 핵심 원리
DataSourceUtils.releaseConnection이 하는 역할에 대해 질문있습니다.
V2까지는 release(con)을 통해 autocommit=true를 진행해줬는데 V3부터는 이 역할을 DataSourceUtils.releaseConnection이 커넥션을 반환하는 것과 동시에 autocommit=true를 담당하는 것이 맞는지 궁금합니다.
-
해결됨스프링 DB 1편 - 데이터 접근 핵심 원리
V0 -> V1으로 전환되는 과정에서 궁금한 점이 생겼습니다.
MemberRepositoryV0에서 직접 만든 DBConnectionUtil을 getConnection을 통해 Connection정보를 가져오는 것인데, 이를 V1에서는 직접 만든 DBConnectionUtil을 dataSource로 변경하고 실제 테스트에서 BeforeEach를 통해 Connection 정보를 주입하는 것인가요?