묻고 답해요
156만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨스프링 DB 1편 - 데이터 접근 핵심 원리
이 테스트 코드가 통과하는 이유
@Test void test(){ Controller controller = new Controller(); Assertions.assertThatThrownBy(()->controller.controller()) .isInstanceOf(RuntimeSQLException.class); } ***************** static class Service{ Repository repository = new Repository(); NetworkClient networkClient = new NetworkClient(); public void service() { repository.call(); networkClient.call(); } } 지금 서비스 로직에서 메서드 두개를 호출했는데 하나는 RuntimeConnectionException이 throw되고 다른 하나는 RuntimeSQLException이 throw가 되는데 테스트 코드가 성공할 수 있나요??
-
미해결토비의 스프링 부트 - 이해와 원리
스프링 spring get/post 보안 관련 문의 드립니다
스프링 spring 보안 관련 문의 드립니다 토비님 안녕하세요 ~여전히 공공기관 프로젝트에 참여 중 인데요스프링 보안 관련 해서 문의 드립니다현재 기 구축되어 있는 프로젝트 소스에서 고도화 및 신규 프로그램 개발 중입니다그러던 중 공공기관 관리자 담당자가보안 관련 지적을 하셨습니다 -.공무원 담당자 지적사항 내용 https://www.url.com?paramA=파라미터a¶mB=파라미터b => 현재 일반 조회는 스프링 겟 매핑 방식 으로 하고 있습니다사이트를 사용하는 일반 유저가브라우저 url 주소창에 파라미터만 수정해가면서 조회 하면조회 결과가 달라져 나오는데 이거 보안상 문제 있는거 아니냐고 따져 지적을 합니다 기 구축되어 있는 소스에는 request 할때따로 인코딩/디코딩이 되어 있지 않는데토비님이 경험해오신 스프링 get/post 보안관련 지적 사항이 나오지 않을려면저희 프로젝트에서 어떻게 전체 소스(js, java ) 에 어떤 보안 관련 기능을 추가 할 수 있을까요? 참고로 구글도 검색어에 '토비' 라고 치고개발자 도구 열어서 payload 보면 한글 그대로 넘어가던데이게 공무원 담당자가 보안 관련 지적 하는게 맞는 건지도저는 모르겠습니다한가하실 때 시간 나시면 조언 부탁 드립니다감사합니다 수고하세요~ 김동희 드림 #토비#토비의스프링#spring#스프링#보안#get#post#parameter#파라미터#문제
-
해결됨스프링 DB 1편 - 데이터 접근 핵심 원리
JDBC 인터페이스와 데이터 소스
둘다 java.sql에 있고"JDBC 인터페이스는 커넥션을 생성하는 방법을 추상화" "데이터소스는 생성된 커넥션을 획득하는 방법을 추상화 " 이 차이가 맞나요??
-
미해결스프링 DB 1편 - 데이터 접근 핵심 원리
커넥션 풀 설정 관련
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)네[질문 내용]강의 잘 보고 있습니다현업에서 보통 와스에서 커넥션 설정시 어떤 프로퍼티를 주로 설정하는지 알고 싶습니다. 그리고 maximumPoolSize = minimumIdle 같은값으로 명시적으로설정하나요?? minimumIdle 을 설정하지 않으면 default 가 maximumPoolSize 와 같으니 설정을 안하는게 맞는지요??(제가 개발자가 아니라 테스트는 못해보고 문의드립니다 .)
-
해결됨스프링 DB 1편 - 데이터 접근 핵심 원리
[제안] H2 데이터베이스 설정
JDBC 이해.pdf 강의 자료 중 H2 데이터베이스 설정 부분에 대해 다음과 같이 추가 제안드립니다. h2 설치 파일을 다운로드 하면 h2.sh 파일을 바로 확인할 수 없어 당황했는데, 강의 영상에서 터미널 path를 보고 bin 디렉토리 안에 파일이 있다는 것을 유추할 수 있었습니다. 이에, 아래와 같이 명시적으로 디렉토리 이동에 대한 내용을 추가하면 다른 수강생분들에게 도움이 될 것 같습니다:)[기존]MAC, 리눅스 사용자 권한 주기: chmod 755 h2.sh 실행: ./h2.sh[추가]MAC, 리눅스 사용자 디렉토리 이동 : cd bin 권한 주기: chmod 755 h2.sh 실행: ./h2.sh
-
미해결스프링 DB 1편 - 데이터 접근 핵심 원리
예외 복구 처리 시 런타임 예외로 전환 필요성
체크 예외를 런타임 예외로 전환하는 것에 대해 의문점이 있습니다.리포지토리에서 체크 예외인 SQLException을 런타임 예외인 MyDBException으로 변환하는 것은 서비스의 SQLException에 대한 의존을 제거하기 위함인데특정 케이스의 예외(중복 키 발생)인 경우 복구를 위해 레퍼지토리에서 에러코드로 SQLException을 분리하고 코드에 따라 다른 런타임 예외를 만들어서 던집니다.이 때 서비스에서는 해당 에러 복구를 위해 try-catch로 결국 해당 런타임 예외를 잡는 코드를 추가해야 합니다. -> 런타임 예외에 대한 종속이 생김 그렇다면 이렇게 예외 처리에 대한 목적이 분명한 경우 SQLException 예외 코드에 따라 (Exception)을 상속받은 체크 예외를 만들어서 던지게 되면 예외를 누락할 위험성도 없고 더 좋은것 아닌가요?-> 어차피 직접 생성한 예외에 대한 종속이 서비스에서 발생하였으므로 왜 굳이 런타임 예외를 상속받은 예외를 생성해서 던지는 지 궁금합니다.
-
해결됨스프링 DB 1편 - 데이터 접근 핵심 원리
커넥션 풀 사용 시 세션 생성 시점
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]커넥션 풀이 10개의 커넥션을 생성하면 세션도 10개가 만들어진다고 하셨는데, 커넥션 풀에 커넥션을 생성하는 시점에 세션이 만들어지는 것인지 아니면 클라이언트가 커넥션 풀의 커넥션을 꺼내서 사용할 때 세션이 만들어지는 것인지 궁금합니다.
-
미해결스프링 DB 1편 - 데이터 접근 핵심 원리
h2 database 연결 방법
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]h2 데이터베이스와 스프링을 연결할 때, application.yml 파일에 datasource 정보를 넣어 연결하는 방법과 해당 강의에서 진행하는 DBConnectionUtil 클래스를 만들어 직접 연결하는 방법이 같은 기능을 수행하는 건가요?
-
미해결토비의 스프링 부트 - 이해와 원리
스프링 검색 유입 경로 pc or 모바일 구분 방법 문의 드립니다
안녕하세요~ 토비님 참여중인 프로젝트가 현재 포탈 사이트 성격입니다 해당프로젝트에서 커뮤니티 기능이 있는데커뮤니티 기능 중에 접속 유입 경로를 따져통계 조회를 해야 하는 기능이 있습니다 개발하는 커뮤니티에 pc 로 접속 할 수 있고 모바일로 접속 할 수 있습니다 PC or 모바일 중어느 기기를 통해서 해당 포탈 커뮤니티에 접속해서 검색했는지따질려면 스프링의 어느 기술 라이브러리를이용해서 따지면 되는지 문의 드립니다감사합니다 수고하세요. 김동희 드림 #sping#스프링#pc#모바일#접속 #구분
-
미해결토비의 스프링 부트 - 이해와 원리
ProxyBeanMethods = false에 대해 궁금합니다.
MyAutoConfiguration에서 ProxyMethods를 false를 줬으니 Tomcat과 DisPatcherServlet이 호출될떄마다 새로 생성되는건가요??
-
해결됨스프링 DB 1편 - 데이터 접근 핵심 원리
왜 commit할 때 status를 넣어줘야 하나요.
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]status는 트랜잭션 설정, 상태에 관한 정보인데, 이미 transactionManager는 생성할 때 dataSource를 넣어줬고, 또 트랜잭션 동기화 매니저가 있기 때문에 어떤 커넥션을 닫아야 할 지 알고 있을 것 같습니다.그럼 commit()할 때난 rollback()할 때 그냥 닫거나 롤백하면 될텐데, 왜 status가 필요한가요?
-
미해결스프링 DB 1편 - 데이터 접근 핵심 원리
Controller에서 BindingResult값을 유지한채로 @ExceptionHandler를 활용한 사용자 정의 예외를 처리하는법이 궁금합니다.
=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]Spring data jpa 를 활용하여 지금까지 배운 내용들을 총 합한 프로젝트를 만들어 보고 있는데 한가지 궁금증이 생겨 질문 드립니다. @ExceptionHandler을 사용하여 사용자정의 예외를 만들어 아이디 중복 예외를 처리하고싶은데 예외를 처리하는 과정에서 아이디가 중복일시 Controller의 BindingResult를 활용하여 아이디가 중복이면 View에 아이디가 중복이라는 정보를 표현하고싶어서 프로젝트를 코딩중에 Controller 부분에서 service단에서 throw한 사용자 정의 예외를 처리하려 하는데 try catch로 예외를 처리하는 순간 @ExceptionHandler를 사용하지 못하고 그렇다고 다시 예외를 던지자니 @ExceptionHandler에서 View에 관련된 Binding result의 값이나 ModelAttribute의 값을 보존해지 못하여 처리가 불가합니다. 이럴때 제일 좋은 방법이 무엇인지 알고싶습니다. Controller 코드입니다.@Controller @RequiredArgsConstructor @RequestMapping("/users") public class UserController { private final LoginService loginService; @GetMapping("/add") public String addForm(@ModelAttribute("userDto") UserDto userDto) { return "user/addUserForm"; } @PostMapping("/add") public String save(@Valid @ModelAttribute UserDto userDto, BindingResult bindingResult) { if (bindingResult.hasErrors()) { return "user/addUserForm"; } // if (loginService.signUpIdExists(userDto.getLoginId()) == false){ // bindingResult.reject("loginIdExists", "동일한 아이디가 존재합니다."); // return "user/addUserForm"; // } try { loginService.signUp(userDto); return "redirect:/"; } catch (UserIdExistsException e) { bindingResult.reject("loginIdExists", "동일한 아이디가 존재합니다."); return "user/addUserForm"; } } } Service 코드입니다.@Slf4j @Service @RequiredArgsConstructor public class LoginService { private final UserRepository userRepository; public User login(String loginId, String password) { return userRepository.findByLoginId(loginId).filter(m -> m.getPassword().equals(password)) .orElse(null); } public void signUp(UserDto userDto) { // if(signUpIdExists(userDto.getLoginId()) == false){ // throw new UserIdExistsException("이미 존재하는 아이디입니다."); // } try { Address address = new Address(userDto.getAddressDto().getZipcode(), userDto.getAddressDto().getStreetAdr(), userDto.getAddressDto().getDetailAdr()); User regisUser = new User(userDto.getLoginId(), userDto.getLoginName(), userDto.getPassword(), address); userRepository.save(regisUser); } catch (DataIntegrityViolationException e) { throw new UserIdExistsException("이미 존재하는 아이디입니다."); } } private boolean signUpIdExists(String loginId) { return userRepository.findByLoginId(loginId).isEmpty(); } } @ControllerAdvice 코드입니다.@Slf4j @ControllerAdvice public class ExceptionAdvice { @ExceptionHandler(UserIdExistsException.class) public ModelAndView userIdExHandler(UserIdExistsException e) { log.error("[userIdExistsException] ex", e); return new ModelAndView(); } } UserIdExistsException 코드입니다.public class UserIdExistsException extends RuntimeException{ public UserIdExistsException() { } public UserIdExistsException(String message) { super(message); } } 위 코드는 동작은 확인했지만 사실상 try catch 로 예외를 잡아버려서 @ExceptionHandler가 동작하지 않는 상태입니다. Entity의 아이디값에 unique 옵션을 걸어두어 아이디 중복이 일어날시 DataIntegrityViolationException에러가 일어납니다.추가로 궁금한것예외가 사실상 repository에서 터지는데 인터페이스에는 try catch가 권장되지 않는것으로 알고 통상 Service에서 에러를 처리하는것으로 알아 이렇게 코딩하였는데 이게 올바른건지 모르겠습니다. 예외를 발생시키는 지점을 repository로 옮기는것이 맞나요? Spring data jpa 는 알아서 Spring에 종속된 에러를 출력하는것으로 알고있는데 DataIntegrityViolationException에 속한 예외 두가지를 다른방법으로 처리하고싶으면 ErrorCode를 분석해 If문 으로 사용자 정의 예외를 만들어서 처리해야하나요? bindingresult를 사용하기 위해 어쩔수없이 예외를 throw하였더니 controller까지 예외가 전파되서 코드가 지저분해졌습니다. 이렇게 View에 특정한 값을 보내주어야할때 Controller에 예외를 throw 하지 않고 해결할수있는 좋은 방법이 있나요? 질문이 길고 지저분해서 죄송합니다. 나름 열심히 알아보고 코딩해보아도 잘 모르겠어서 질문남깁니다. 감사합니다.
-
해결됨스프링 DB 1편 - 데이터 접근 핵심 원리
리소스 정리
트랜잭션 매니저의 전체 동작 흐름에서 마지막에 '전체 리소스를 정리한다.' 라고 나와있는데 코드상으로 어디 부분에서 리소스 정리가 일어나는 건가요? 커밋이나 롤백을 하고 리소스 정리를 하는 코드가 내부에 존재하는 건가요?
-
미해결스프링 DB 1편 - 데이터 접근 핵심 원리
Test 오류 발생 원인이 무엇인지 잘 모르겠습니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]package hello.jdbc.service; import hello.jdbc.domain.Member; import hello.jdbc.repository.MemberRepositoryV3; import lombok.extern.slf4j.Slf4j; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionTemplate; import java.sql.SQLException; /** * 트랙잭션 - @Transactional AOP */ @Slf4j //final이 붙거나 @NotNull 이 붙은 필드의 생성자를 자동 생성해주는 롬복 어노테이션 public class MemberServiceV3_3 { private final MemberRepositoryV3 memberRepository; public MemberServiceV3_3( MemberRepositoryV3 memberRepository) { this.memberRepository = memberRepository; } @Transactional //이 메소드를 호출할 때, 트랙잭션을 걸고 시작하겠다는 의미. // 성공하면 커밋 실패하면 롤백을 한다. public void accountTransfer(String fromId, String toId, int money) throws SQLException { bizLogic(fromId, toId, money); } private void bizLogic(String fromId, String toId, int money) throws SQLException { Member fromMember = memberRepository.findById(fromId); Member toMember = memberRepository.findById(toId); memberRepository.update(fromId,fromMember.getMoney()- money); validation(toMember); memberRepository.update(toId,toMember.getMoney()+ money); } private static void validation(Member toMember) { if(toMember.getMemberId().equals("ex")){ throw new IllegalStateException("이제 중 예외 발생. 테스트 위해 만듦"); } } }이것이 원본 코드이고 package hello.jdbc.service; import hello.jdbc.domain.Member; import hello.jdbc.repository.MemberRepositoryV3; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.transaction.PlatformTransactionManager; import javax.sql.DataSource; import java.sql.SQLException; import static hello.jdbc.connection.ConnectionConst.*; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; /** * 트랜잭션 - @Transactional AOP */ @Slf4j @SpringBootTest //스프링테스트 어노테이션이 있으면 이 테스트에서 //스프링부트가 이 테스트에서 스프링 컨테이너를 만들고 필요한 스프링 빈을 전부 등록하고 스프링 빈에 대한 의존관계 주입도 받을 수 있게 된다 class MemberServiceV3_3Test { public static final String MEMBER_A = "memberA"; public static final String MEMBER_B = "memberB"; public static final String MEMBER_EX = "ex"; @Autowired // 의존관계 주입을 받아서 사용한다. private MemberRepositoryV3 memberRepository; @Autowired private MemberServiceV3_3 memberService; @TestConfiguration static class TestConfig{ @Bean DataSource dataSource(){ return new DriverManagerDataSource(URL,USERNAME,PASSWORD); } @Bean PlatformTransactionManager transactionManager(){ return new DataSourceTransactionManager(dataSource()); } @Bean MemberRepositoryV3 memberRepositoryV3(){ return new MemberRepositoryV3(dataSource()); } @Bean MemberServiceV3_3 memberServiceV3_3(){ return new MemberServiceV3_3(memberRepositoryV3()); } } @AfterEach void after() throws SQLException { memberRepository.delete(MEMBER_A); memberRepository.delete(MEMBER_B); memberRepository.delete(MEMBER_EX); } @Test @DisplayName("정상 이체") void accountTransfer() throws SQLException { //given Member memberA = new Member(MEMBER_A, 10000); Member memberB = new Member(MEMBER_B, 10000); memberRepository.save(memberA); memberRepository.save(memberB); //when memberService.accountTransfer(memberA.getMemberId(), memberB.getMemberId(), 2000); //then Member findMemberA = memberRepository.findById(memberA.getMemberId()); Member findMemberB = memberRepository.findById(memberB.getMemberId()); assertThat(findMemberA.getMoney()).isEqualTo(8000); assertThat(findMemberB.getMoney()).isEqualTo(12000); } @Test @DisplayName("이체중 예외 발생") void accountTransferEx() throws SQLException { //given Member memberA = new Member(MEMBER_A, 10000); Member memberEx = new Member(MEMBER_EX, 10000); memberRepository.save(memberA); memberRepository.save(memberEx); //when assertThatThrownBy(() -> memberService.accountTransfer(memberA.getMemberId(), memberEx.getMemberId(), 2000)) .isInstanceOf(IllegalStateException.class); //then Member findMemberA = memberRepository.findById(memberA.getMemberId()); Member findMemberEx = memberRepository.findById(memberEx.getMemberId()); //memberA의 돈이 롤백 되어야함 assertThat(findMemberA.getMoney()).isEqualTo(10000); assertThat(findMemberEx.getMoney()).isEqualTo(10000); } }이것이 테스트 코드입니다.원본 코드는 따로 수정하지 않았고 테스트 코드만 가져와서 사용했는데 왜 오류가 발생하는지 잘 이해가 안됩니다 설명 부탁드립니다. 오류는 다음과 같이 나옵니다Execution failed for task ':test'.> No tests found for given includes: [hello.jdbc.service.MemberServiceV3_3Test.AopCheck](--tests filter)* Try:> Run with --stacktrace option to get the stack trace.> Run with --info or --debug option to get more log output.> Run with --scan to get full insights.> Get more help at https://help.gradle.org.Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0.You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.For more on this, please refer to https://docs.gradle.org/8.2.1/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation.BUILD FAILED in 577ms4 actionable tasks: 1 executed, 3 up-to-date 설명 부탁드립니다
-
미해결스프링 DB 1편 - 데이터 접근 핵심 원리
MemberServiceV3_3 테스트 코드 질문 있습니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]위는 MemberServiceV3_3 코드의 @Transactional를 사용하는 메소드 부분이고 아래는 MemberServiceV3_3Test 코드입니다.package hello.jdbc.service; import hello.jdbc.domain.Member; import hello.jdbc.repository.MemberRepositoryV3; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.transaction.PlatformTransactionManager; import javax.sql.DataSource; import java.sql.SQLException; import static hello.jdbc.connection.ConnectionConst.*; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; /** * 트랜잭션 - @Transactional AOP */ @Slf4j @SpringBootTest //스프링테스트 어노테이션이 있으면 이 테스트에서 //스프링부트가 이 테스트에서 스프링 컨테이너를 만들고 필요한 스프링 빈을 전부 등록하고 스프링 빈에 대한 의존관계 주입도 받을 수 있게 된다 class MemberServiceV3_3Test { public static final String MEMBER_A = "memberA"; public static final String MEMBER_B = "memberB"; public static final String MEMBER_EX = "ex"; @Autowired // 의존관계 주입을 받아서 사용한다. private MemberRepositoryV3 memberRepository; @Autowired private MemberServiceV3_3 memberService; @TestConfiguration static class TestConfig{ @Bean DataSource dataSource(){ return new DriverManagerDataSource(URL,USERNAME,PASSWORD); } @Bean PlatformTransactionManager transactionManager(){ return new DataSourceTransactionManager(dataSource()); } @Bean MemberRepositoryV3 memberRepositoryV3(){ return new MemberRepositoryV3(dataSource()); } @Bean MemberServiceV3_3 memberServiceV3_3(){ return new MemberServiceV3_3(memberRepositoryV3()); } } @AfterEach void after() throws SQLException { memberRepository.delete(MEMBER_A); memberRepository.delete(MEMBER_B); memberRepository.delete(MEMBER_EX); } @Test @DisplayName("정상 이체") void accountTransfer() throws SQLException { //given Member memberA = new Member(MEMBER_A, 10000); Member memberB = new Member(MEMBER_B, 10000); memberRepository.save(memberA); memberRepository.save(memberB); //when memberService.accountTransfer(memberA.getMemberId(), memberB.getMemberId(), 2000); //then Member findMemberA = memberRepository.findById(memberA.getMemberId()); Member findMemberB = memberRepository.findById(memberB.getMemberId()); assertThat(findMemberA.getMoney()).isEqualTo(8000); assertThat(findMemberB.getMoney()).isEqualTo(12000); } @Test @DisplayName("이체중 예외 발생") void accountTransferEx() throws SQLException { //given Member memberA = new Member(MEMBER_A, 10000); Member memberEx = new Member(MEMBER_EX, 10000); memberRepository.save(memberA); memberRepository.save(memberEx); //when assertThatThrownBy(() -> memberService.accountTransfer(memberA.getMemberId(), memberEx.getMemberId(), 2000)) .isInstanceOf(IllegalStateException.class); //then Member findMemberA = memberRepository.findById(memberA.getMemberId()); Member findMemberEx = memberRepository.findById(memberEx.getMemberId()); //memberA의 돈이 롤백 되어야함 assertThat(findMemberA.getMoney()).isEqualTo(10000); assertThat(findMemberEx.getMoney()).isEqualTo(10000); } }저는 지금까지는 원본 코드와 테스트 코드가 따로 따로라고 생각했습니다. 근데 강의에서 원본 코드의 @Transactional을 사용 했을 때와, @Transactional을 주석 처리해 원본 코드를 수정했을 때. 테스트 코드의 결과가 다르게 변하더라구요. 이런 결과가 왜 발생하는건가요?테스트 코드는 원본 코드에 영향을 받는건가요?만약, 영향을 받는다면 어떤 범위까지 영향을 받는건가요? 설명 부탁드립니다!
-
미해결스프링 DB 1편 - 데이터 접근 핵심 원리
커넥션과 세션의 관계, 세션과 트랜잭션의 관계가 궁금합니다.
질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]스프링 DB 1편 트랜잭션 이해 파트에서 질문입니다."애플리케이션에서 DB 트랜잭션을 사용하려면 트랜잭션을 사용하는 동안 같은 커넥션을 유지해야한다. 그래야 같은 세션을 사용할 수 있다" 여기서 세션의 개념이 정확히 이해가 가지 않아 질문드립니다.찾아본 결과 하나의 커넥션에는 여러 개 세션이 존재할 수도, 아예 없을 수도 있다고 하고, 세션은 전달된 SQL이 실행되는 하나의 논리적 단위라고 합니다. 강의 설명에 따르면 같은 세션을 유지해야만 트랜잭션이 하나의 단위로 처리되기 때문에 이를 위해 같은 커넥션을 사용해야 한다고 이해했습니다. 그렇다면 같은 커넥션을 사용하는 것을 보장했을 때 항상 같은 세션을 사용하는 것도 보장되는 것인가요? 한 커넥션이 여러 세션을 사용하는 경우는 어떤 경우인가요? 여러 세션을 사용하게 되면 여러 세션에서 여러 개의 트랜잭션이 실행될 수 있는 것인가요?
-
해결됨스프링 DB 1편 - 데이터 접근 핵심 원리
@Transaction 적용 시 수동 빈 등록 관련 질문
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]@Transaction을 사용 시, 스프링 AOP가 적용되어야 하기 때문에 테스트 코드에서는 @SpringBootTest와 함께 트랜잭션 적용에 필요한 다양한 객체를 수동으로 등록하고 적용하는 법을 배웠습니다. (PlatforTransactionManager, DataSource 등) 그러면 테스트 환경이 아닌 서비스 로직에서 @Transaction을 사용할 경우에는 강의에서 진행한 수동 빈 등록 절차를 거치지 않아도 되는 건가요? @Transcation을 썼을 때 트랜잭션에 필요한 빈들을 자동으로 등록한다는 내용이 이 뜻인건지 궁금합니다.
-
미해결토비의 스프링 부트 - 이해와 원리
스프링 사용 관련 궁금한 사항이 생겨 질문드립니다
스프링 사용 관련 궁금한 사항이 생겨 질문드립니다 토비님 안녕하세요~ 오늘 아침에 웹프로그램 개발하다 갑자기 궁금한 사항이 생겼습니다 1. MVC 컨트롤러 를 이용 할 때 보안상 문제로 get을 사용하지 않고 post 만 작성 하는게 맞는것인지 웹프로그램을 개발 할 때 브라우저 url 에는 파라미터가 전혀 안보이는것이 보안상 최선인지 궁금합니다 토비님도, 스프링 mvc 를 이용해서 개발 하실때 모두 post 방식으로 request 를 하시는지 궁금합니다 (간혹 금융권 사이트에서는 url 부분에 파라미터가 안보였던거 같아서요.. ) 2. 네이버/카카오/유튜브 open API 등을 누가나 사용 할 수 있는데요 나쁜 사용자가 악의적인 의도를 갖고 마구 request 호출 을 할 경우 서버 트랙픽을 방어 하려고 하면 스프링의 어느 기술을 이용해서 막을 수 있을 까요? 3. 스프링 프레임웍 안에서 뷰(프론트) 부분에 JSP / 타임리프 / php / react / vue 동시에 여러가지를 함께 쓸 수가 있나요? 감사합니다. 수고하세요
-
해결됨스프링 DB 1편 - 데이터 접근 핵심 원리
동시성 이슈 처리 질문있습니다!
DB 동시성 문제를 해결하기 위해낙관적 잠금, 유니크 제약조건, 비관적 잠금이 있는 것으로 알고있습니다.비관적 잠금은 성능상의 이유로 잘 사용하지 않는다고 알고있어서낙관적 잠금 또는 유니크 제약조건으로 동시성을 해결하고 있는데, 낙관적 잠금을 사용해야 할지, 유니크 제약 조건을 사용해야 할지 의문이 들어 질문 드립니다. 감사합니다!
-
해결됨토비의 스프링 부트 - 이해와 원리
커스톰 @Conditional 강의에서 질문입니다.
<해결됨>같은 질문 링크입니다. https://www.inflearn.com/chats/757401/x27-conditional%EA%B3%BC-condition-x27-%EA%B0%95%EC%9D%98-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B83-0-%EC%9D%B4%EC%83%81%EC%9C%BC%EB%A1%9C-%EC%95%88%EB%90%98%EB%8A%94%EB%B6%84%EB%93%A4 https://github.com/tobyspringboot/helloboot/commit/9db7fbb4b665ad0a21e18fa580d378179b44fa92spring boot 3에서 적용해보고 있습니다.제목의 강의에 해당하는 커밋은 위 링크일 것 같습니다. 해당 커밋에서 checkout 한 후, dependencies { implementation('org.springframework.boot:spring-boot-starter-web') { exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat' } implementation 'org.springframework.boot:spring-boot-starter-jetty' testImplementation 'org.springframework.boot:spring-boot-starter-test' } 위와 같이 jetty를 사용하게 해두고 어플리케이션을 실행하면 Unable to start web server, java.lang.NoClassDefFoundError: jakarta/servlet/http/HttpSessionContext 오류는 jakarta.servlet.http 패키지의 HttpSessionContext 자바 클래스를 찾을 수 없음이렇게 나오는 것 같습니다.어떻게 해결할 수 있을까요..?