묻고 답해요
164만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
protected 사용 이유
안녕하세요! 해당 강의에서 기본 생성자를 추가해주실 때, public이 아니라 protected를 사용하셨는데, 그 이유가 무엇인가요?혹시라도 다른 곳에서 기본생성자를 사용하지 못하도록 하게 하기 위함인가요? 제가 자바가 안익숙해서 그런지, 이러한 접근 제어자를 쓰는 것이나, static, final 키워드를 언제 쓰거나 안써야 하는지에 대한 감이 별로 없어서 구분을 잘 못하는데, 이러한 실력은 어떤 경험을 더 쌓아야 할지.. 아니면 어떤 키워드를 어떻게 공부해야 더이상 안 헷갈리고 확실하게 알 수 있을지 궁금합니다...! 항상 친절한 강의 감사드립니다.
-
해결됨스프링 부트 - 핵심 원리와 활용
server project import 시 에러 발생
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오) 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 예[질문 내용]server 프로젝트를 gradle import 시 아래와 같은 에러가 발생합니다.The supplied phased action failed with an exception.Could not open cp_init generic class cache for initialization script 'C:\2023-12-JAVA-DEVELOPER\spring-workspace\.metadata\.plugins\org.eclipse.buildship.core\init.d\eclipsePlugin.gradle' (~~\.gradle\caches\7.5\scripts\exvtfib8x4d7xhxmo1dku6nlm).BUG! exception in phase 'semantic analysis' in source unit '_BuildScript_' Unsupported class file major version 65Unsupported class file major version 65 해결 방법이 궁금합니다.(+추가) 프로젝트의 gradle version을 최신 버전으로 높이니 import까진 성공했는데, src 폴더가 생성되질 않았습니다. 그냥 제가 수동으로 생성해서 쓰면 될까요?
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
데이터베이스 테이블에서 해당 컬럼을 찾을 수 없음이 뜹니다.
JPA 코드를 다 작성하고 실행하려고 할 때 DB에서 해당 컬럼을 찾을 수 없다고 뜨네요아래는 에러코드입니다.org.hibernate.exception.SQLGrammarException: could not prepare statement [Column "M1_0.USERNAME" not found; SQL statement: select m1_0.id,m1_0.username from member m1_0 where m1_0.username=? [42122-224]] [select m1_0.id,m1_0.username from member m1_0 where m1_0.username=?]package hello.hellospring.repository; import hello.hellospring.domain.Member; import jakarta.persistence.EntityManager; import jakarta.persistence.*; import java.util.List; import java.util.Optional; public class JpaMemberRepository implements MemberRepository { private final EntityManager em; public JpaMemberRepository(EntityManager em) { this.em = em; } public Member save(Member member) { em.persist(member); return member; } public Optional<Member> findById(Long id) { Member member = em.find(Member.class, id); return Optional.ofNullable(member); } public List<Member> findAll() { return em.createQuery("select m from Member m", Member.class) .getResultList(); } public Optional<Member> findByName(String name) { List<Member> result = em.createQuery("select m from Member m where m.name = :name", Member.class) .setParameter("name", name) .getResultList(); return result.stream().findAny(); } } 위에는 JpaMemberRepository 코드이고아래는 테스트 코드입니다.테스트 코드에서 오류가 발생 할 때 memberService.join에 빨간 밑줄이 생깁니다.그리고 디버그 해보면 JpaMemberRepository 코드에서 findByName에 쿼리문 쪽에 문제가 발생했다고 뜹니다.. 코드는 다 똑같이 작성했는데 뭐가 문제일까요 ㅠㅠpackage hello.hellospring.service; import hello.hellospring.domain.Member; import hello.hellospring.repository.MemberRepository; import hello.hellospring.repository.MemoryMemberRepository; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.transaction.annotation.Transactional; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; @SpringBootTest @Transactional class MemberServiceIntegrationTest { @Autowired MemberService memberService; @Autowired MemberRepository memberRepository; @Test void 회원가입() { //given Member member = new Member(); member.setName("spring"); //when Long saveId = memberService.join(member); //then Member findMember = memberService.findOne(saveId).get(); assertThat(member.getName()).isEqualTo(findMember.getName()); } @Test public void 중복_회원_예외() { //given Member member1 = new Member(); member1.setName("spring"); Member member2 = new Member(); member2.setName("spring"); //when memberService.join(member1); IllegalStateException e = assertThrows(IllegalStateException.class, () -> memberService.join(member2)); assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다."); } }
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
h2에서 회원 조회가 안 됩니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]실행은 되는데 h2에서 select * from member; 했을 때 조회되는 게 없다면 어디 부분이 문제일까요..? 원래는 됐었는데 갑자기 인텔리제이에서 회원가입부분 실행하다 오류가 나면서 이것저것 수정해보다가 이 상황이 되었습니다..그리고 Hibernate: select m1_0.id,m1_0.name from member m1_0 where m1_0.name=?Hibernate: insert into member (name,id) values (?,default)Hibernate: select m1_0.id,m1_0.name from member m1_0 where m1_0.name=?Hibernate: select m1_0.id,m1_0.name from member m1_0 where m1_0.name=?Hibernate: insert into member (name,id) values (?,default) 이렇게 강사님 화면과 다르게 id와 name의 자리가 바뀌어 나오는데 잘못된 걸까요..?섹션 6까지는 들은 상태입니다.
-
해결됨장애 없는 서비스를 만들기 위한 Resilience4j - CircuitBreaker
강의 자료 문의
안녕하세요. 강의에서 사용한 ppt 자료 어디서 받을 수 있는지 궁금합니다. 감사합니다.
-
해결됨스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
리포지토리를 다른것으로 변경시 어노테이션만 다른곳으로 옮기면 되나요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]의존관계 자동 주입을 위해 @Repository를 사용하였는데 메모리멤버맃포지토리가 아닌 데이타베이스멤버리포지토리를 사용하려면 메모리멤버리포지토리에 있는 @Repository어노테이션을 지우고 실제 사용할 데이타베이스멤버리포지토리에 @Repository어노테이션을 사용하면 되나요?
-
미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
왜 요청에다가 AthenticFilter를 적용할까요?
apigateway의 application.yml을 보면 get요청에는 authorizationHeaderFilter를 적용시키고 있습니다. authenticFilter는 그저 로그인 요청시 attempthAuthentication메소드와 successfulAthentication메소드를 통해 인증을 처리하고 response헤더에 토큰을 추가하는 역할입니다. 따라서 로그인 요청에만 적용하면 될 것 같은데, 깃허브의 최신코드 버전을 보면 거의 모든 요청에 authenticationFilter를 적용하고 있습니다. 왜 로그인요청이 아닌 다른 요청에다가 AthenticFilter를 적용할까요? apiGateway-service에서 GET요청만 AuthoriztionFilter를 적용하면 되지않나요??http.authorizeHttpRequests((authz) -> authz .requestMatchers(new AntPathRequestMatcher("/actuator/**")).permitAll() .requestMatchers(new AntPathRequestMatcher("/h2-console/**")).permitAll() .requestMatchers(new AntPathRequestMatcher("/users", "POST")).permitAll() .requestMatchers(new AntPathRequestMatcher("/h2-console/**")).permitAll() // .requestMatchers(new AntPathRequestMatcher("/welcome/**")).permitAll() // .requestMatchers("/**").access(this::hasIpAddress) .requestMatchers("/**").access( new WebExpressionAuthorizationManager("hasIpAddress('127.0.0.1') or hasIpAddress('172.30.1.48')")) .anyRequest().authenticated() )
-
해결됨스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
Mvc방식에서 메서드의 파라미터에 Model model을 사용하는 이유가 무엇인가요? 그리고 api방식에서의 질문이 있습니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]뒷 내용이 어려워서 다시 복습하는중인데 파라미터에 Model model을 사용하는 이유가 궁금합니다. 파라미터로 받지 않고 메서드 내부에서 Model model;model.addAttribute(모델데이타, value); 이렇게 사용할 수 는 없는건가요? 그리고 api통신에서 어노테이션에 @ResponseBody를 확인하면 html로 반환하지 않는다고 인식 후 return이 스트링인지 객체인지 확인 후 어떤 형식으로 반환할지 정해지는것인가요?객체를 반환할 때 서버에 반환하던 웹 브라우저에 반환하던 스프링은 누구에게 반환을 하는건지 몰라도 되는것인가요? 예를 들면 현 강의에서는 웹 브라우저에 반환을 하였지만 리액트를 이용할 때는 노드환경(노드환경을 서버로 이해하였습니다.)에 반환을 하는 방식인데 스프링은 요청한 주체와 반환되는 값이 어디로 가는지는 알 필요가 없는건가요?
-
미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
로그인까지는 되는데 /welcome에서 403 Forbidden 에러가 뜹니다.
안녕하세요. 깃허브에서 spring boot 3.2 브랜치통해 코드를 작성했습니다. 그런데 회원가입, 로그인까지 해서 jwt토큰까지는 잘 받아오는데, 그 이후에 /welcome으로 헤더에 토큰으로 추가해서 요청을 보내도 403 forbidden에러가 뜹니다. 코드는 spring boot 3.2 브랜치와 동일합니다.
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
현재 1강 테스트중 오류내용입니다.
MemberRepositoryTest를 작성하고 실행하면 자꾸 이 오류가 뜨는데 이유를 모르겠습니다..
-
미해결실전! 스프링부트 상품-주문 API 개발로 알아보는 TDD
실무 Asserta 사용여부가 궁금합니다.
안녕하세요 강의를보다가 validation 검사를Assert Class를 활용하여 하고 계시던데실무에서도 자주 쓰는 문법인지 궁금합니다.
-
미해결자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
mysql 실행 질문
국비 수료 후 선생님 강의 듣고 있습니다.저는 오라클을 db로 사용했었고 그 땐 sql디벨로퍼를 주로 사용했었는데요전 인텔리제이 무료버전이라 mysql command line client를사용해야 할텐데 제가 궁금한건오라클에서 sql디벨로퍼를 사용했더라면 그에 대응되는게인텔리제이의 mysql command line client라 보면 될까요? sql디벨로퍼에선 테이블도 가시적으로 보이고 셀렉트 해서 조회하는 결과도 보였는데 mysql command line client 같은 경우 리눅스형식같고 뭔가 좀 어색해서용
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
h2접속 test.mv.db 파일 생성
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요.접속까지는 되는데 test.db.mv 파일이 만들어지지가 않아서 jdbc:h2:tcp://localhost/~./test 접속이 안됩니다 이걸로
-
해결됨스프링 시큐리티 OAuth2
apply 대체
최신버전에서 apply가 deprecated되어서 자료를 좀 찾아봤습니다만, 확신이 없어서 질문드립니다.@EnableWebSecurity @Configuration public class SecurityConfig { @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(authorize -> authorize .anyRequest().authenticated() ) .formLogin(withDefaults()) .with(new CustomSecurityConfigurer().setFlag(true), withDefaults()); return http.build(); } }대체로 with을 사용한다고 하는데, Customizer.withDefaults를 두번째 인자로 주었습니다.이렇게 사용하는 것이 맞나요?Customizer의 역할도 조금만 알려주시면 감사하겠습니다. 기존 프로젝트에 대입하려니 최신 관련 자료가 너무나 없네요... ㅠㅠ
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
문득 ArrayList 에 대해 궁금해졌습니다.
[질문 내용]안녕하세요! ArrayList 에 대해 이것저것 찾아보던 중 이런 내용이 있었습니다. ArrayList,Map 은 동시성 이슈가 있어 ArrayList 대신 CopyOnWriteArrayList를 Map 대신 ConCurrentHashMap 을 쓰라는 내용이었습니다. 이에 대해 실제 스프링으로 개발할 때 위 내용이 어떻게 응용되는지 이해가 안되고 찾지 못해서 질문드립니다. 뭐 단순히 ArrayList 에 정수 넣고 실험해서 동시성 이슈가 있다라고 파악을 한다고 치더라도 뭐 어느 경우에 적용해야 하는지 이해가 안갑니다. 질문 요약 1) ArrayList 대신 CopyOnWriteArrayList 를 써야 하는 실무적인 실제 예를 들어주세요! 지금까지 영한님한테 배웠던 대로 양방향 관계에서 List = new ArrayList<>로 초기화 해줬는데 그러면 이는 유저가 많은 멀티스레드 환경에서 위험한 것 아닌가요?? public PostResponseDto showDetailsPost(final Long postId){ //Post + PostImage + Post 게시글 작성자 함께 영속화 Post post = findPostWithFetchMemberAndImage(postId); //첫 댓글 Reply (대댓글 X) + 부모댓글 작성자 함께 영속화 List<Reply> parentReply = replyRepository.findParentReplyByPostIdWithFetchMember(postId); List<ReplyResponseDto> replyResponseDtoList = new ArrayList<>(); //부모-> 자식 순으로 DTO 순서 저장. for(Reply parent: parentReply){ replyResponseDtoList.add(ReplyResponseDto.of(parent,makeNickNameForReply(parent),makeContentsForReply(parent)));위 코드는 List<ReplyResponseDto> 를 new ArrayList<>() 로 초기화 해서 add 로 넣어주는 부분이 있습니다. 이런 부분도 다 CopyOnWriteArrayList를 써야 하는 것인가요? 2) Map 도 마찬가지입니다. 실제 Map 대신 ConcurrentHashMap 을 써야 했던 실무적인 예를 들어주시면 감사하겠습니다.
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
어노테이션 질문이있습니다.
안녕하세요 질문이 있습니다 API 강의 듣다가 궁금증이 생겨서 질문을 남기게 되었습니다. @RequestParam 은 매개변수의 값을 반환하는건가요?@RequestMapping("/save") public ModelAndView save(HttpServletRequest request, HttpServletResponse response) { String username = request.getParameter("username"); int age = Integer.parseInt(request.getParameter("age")); ... }이 코드를@PostMapping("/save") public String save(@RequestParam("username") String username, @RequestParam("age") int age, Model model) { ... }요렇게 바꿔줄 수 있는 역할이 @RequestParam 인 건가요? 그리고 RequestParam 을 쓸때 달아주는 어노테이션이 @ResponseBody 인건가요??
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
학습방향 질문드립니다
안녕하세요 mvc강의를 2편까지 모두 듣고 야생형코스를 따라가려고 jpa1편을 수강중입니다.현재 섹션2까지 들었는데 도메인 분석과 엔티티설계시 강사님께서 설명해주신 다대다관계, 연관관계 메서드 등 확실히 이해는 안가지만 이런게 있구나 하며 넘어가도 되는걸까요?이 강의에서는 jpa를 알아가보는 것보다 스프링에서 jpa를 어떻게 쓰는지만 알고 이 강의 듣고 기본편으로 넘어가도 되는걸까요?
-
해결됨스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
트랜잭션 시작
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]pdf에 @Transactional 설명하는 부분에서 테스트 시작 전에 트랜잭션을 시작하고~ 라는 말이 있는데, 여기서 말하는 트랜잭션이 시작한다는게 무엇을 시작한다는 건가요?
-
미해결실전! 스프링 데이터 JPA
낙관적 락에 대해 질문이 있습니다.
Hibernate는 @Version을 사용하고, Lock 옵션을 @Lock(LockModeType.OPTIMISTIC)을 사용할 경우에 NONE 모드와 다르게 엔티티를 수정하지 않고 단순히 조회만 해도 버전을 확인한다고 강사님 JPA 책에 작성되어있습니다. 실제 코드로 구현해보니 버전만 확인하는거 같더라구요그 사이에 다른 트랜잭션이 해당 엔티티를 수정하여 버전이 변경되어도 ObjectOptimisticLockingFailureException 예외가 발생하지 않습니다. 간단하게 로직을 설명드리면 트랜잭션 A가 옵티미스틱 락 모드로 회원을 조회합니다. version = 0트랜잭션 A를 5초 대기합니다.트랜잭션 B가 회원을 수정하여 버전이 변경됩니다. version = 1트랜잭션 B가 종료됩니다.5초가 지나 트랜잭션 A가 종료됩니다.트랜잭션 A가 종료될 때 옵티미스틱 락 모드라서 마지막에 버전을 확인합니다.select version as version_ from member where id=?그런데 트랜잭션 A가 종료될때에 회원 버전이 다르지만 예외가 발생하지 않습니다. 이러면 OPTIMISTIC의 용도가 트랜잭션을 커밋할 때 버전 정보를 조회해서 현재 엔티티의 버전과 같은지 검증한다. 만약 같지 않으면 예외가 발생한다고 작성되어있는데 예외가 발생하지 않는다면 강사님께서 설명해주신 조회한 엔티티는 트랜잭션이 끝날 때까지 다른 트랜잭션에 의해 변경되지 않아야한다. 조회 시점부터 트랜잭션이 끝날때까지 조회한 엔티티가 변경되지 않음을 보장한다.이 말의 다른 의미가 어떤건지 궁금합니다 !아니면 제가 테스트를 잘못하고 있는 걸까요..? 아래는 로직에 대한 간단한 코드입니다.도메인package org.example.stock_rt_1.domain; import jakarta.persistence.*; import lombok.Getter; import lombok.NoArgsConstructor; @Entity @Getter @NoArgsConstructor public class Member { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) public Long id; private long personId; private int age; @Version private Long version; public Member(long personId, int age) { this.personId = personId; this.age = age; } public void addAge() { ++this.age; } }리포지토리package org.example.stock_rt_1.repository; import jakarta.persistence.LockModeType; import org.example.stock_rt_1.domain.Member; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Lock; import java.util.Optional; public interface MemberRepository extends JpaRepository<Member, Long> { @Lock(LockModeType.OPTIMISTIC) Optional<Member> findByPersonId(Long id); }서비스package org.example.stock_rt_1.service; import lombok.RequiredArgsConstructor; import org.example.stock_rt_1.domain.Member; import org.example.stock_rt_1.repository.MemberRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Optional; @Service @RequiredArgsConstructor public class MemberService { public final MemberRepository memberRepository; @Transactional public void addAge(long personId) { sleep(500); //findMember가 먼저 실행되야하기 때문에 넣었습니다. Member member = memberRepository.findByPersonId(personId).orElseThrow(); member.addAge(); } @Transactional public void findMember(long personId) { memberRepository.findByPersonId(personId); sleep(5000); } private void sleep(long mills) { try { Thread.sleep(mills); } catch (InterruptedException e) { System.out.println("e = " + e.getMessage()); } } }테스트코드package org.example.stock_rt_1.service; import org.example.stock_rt_1.domain.Member; import org.example.stock_rt_1.repository.MemberRepository; 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; @SpringBootTest class MemberServiceTest { @Autowired private MemberService memberService; @Autowired private MemberRepository memberRepository; @Test @DisplayName("회원 정보를 조회중 다른 트랜잭션에서 정보를 변경했다.") void addAge() throws InterruptedException { // given int personId = 5555; memberRepository.save(new Member(personId,15)); // when Thread selectThread = new Thread(() -> memberService.findMember(personId),"트랜잭션-A"); selectThread.start(); Thread updateThread = new Thread(() -> memberService.addAge(personId),"트랜잭션-B"); updateThread.start(); selectThread.join(); updateThread.join(); } }로그[트랜잭션-A] : select m1_0.id,m1_0.age,m1_0.person_id,m1_0.version from member m1_0 where m1_0.person_id=? Hibernate: select m1_0.id,m1_0.age,m1_0.person_id,m1_0.version from member m1_0 where m1_0.person_id=? [트랜잭션-B] : select m1_0.id,m1_0.age,m1_0.person_id,m1_0.version from member m1_0 where m1_0.person_id=? Hibernate: select m1_0.id,m1_0.age,m1_0.person_id,m1_0.version from member m1_0 where m1_0.person_id=? [트랜잭션-B] : update member set age=?,person_id=?,version=? where id=? and version=? [트랜잭션-B] : select version as version_ from member where id=? [트랜잭션-A] : select version as version_ from member where id=?
-
미해결실전! 스프링 데이터 JPA
PageRequest, pageable
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]이전 강의에서는 PageRequest.of(pagenum, pagesize, sort.by()) 를 사용해서 직접 설정해줘서 리포지토리 매서드에 인자로 넘겼는데 mvc의 @PageableDefault를 사용하면 이런 부분을 자동으로 처리해준다라고 이해해도 괜찮을까요?