묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
open-in-view값 true/false
@Controller @RequiredArgsConstructor @RequestMapping("/board") public class BoardController { @PostMapping("/update") public String update(@ModelAttribute BoardDTO boardDTO, Model model) { BoardDTO board = boardService.update(boardDTO); model.addAttribute("board", board); return "detail"; } } @Service @RequiredArgsConstructor public class BoardService { private final BoardRepository boardRepository; public BoardDTO findById(Long id) { System.out.println("findById : "+ em.getDelegate()); // 이 아래 코드에서 질문 있습니다. Optional<BoardEntity> optionalBoardEntity = boardRepository.findById(id); if (optionalBoardEntity.isPresent()) { BoardEntity boardEntity = optionalBoardEntity.get(); return BoardDTO.toBoardDTO(boardEntity); } else { return null; } } public BoardDTO update(BoardDTO boardDTO) { System.out.println("update : "+ em.getDelegate()); BoardEntity boardEntity = BoardEntity.toUpdateEntity(boardDTO); boardRepository.save(boardEntity); return findById(boardDTO.getId()); } } @MappedSuperclass @EntityListeners(AuditingEntityListener.class) @Getter public class BaseEntity { @CreationTimestamp @Column(updatable = false) private LocalDateTime createdTime; @UpdateTimestamp @Column(insertable = false) private LocalDateTime updatedTime; } @Entity @Getter @Setter @Table(name = "board_table") public class BoardEntity extends BaseEntity { @Id GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String boardWriter; private String boardPass; private String boardTitle; private String boardContents; private int boardHits; public static BoardEntity toUpdateEntity(BoardDTO boardDTO) { BoardEntity boardEntity = new BoardEntity(); boardEntity.setId(boardDTO.getId()); boardEntity.setBoardWriter(boardDTO.getBoardWriter()); boardEntity.setBoardPass(boardDTO.getBoardPass()); boardEntity.setBoardTitle(boardDTO.getBoardTitle()); boardEntity.setBoardContents(boardDTO.getBoardContents()); boardEntity.setBoardHits(boardDTO.getBoardHits()); return boardEntity; } } 위에 코드 상황에서 open-in-view를 true로 하면 optionalBoardEntity에 createdTime 값이 null입니다. 제 생각으로는 open-in-view가 true 이므로 update()에서 (createdTime 값이 없는) boardEntity가 영속성 컨텍스트 1차 캐시에 존재하고, findById()에서 boardRepository.findById(id) 값을 호출하지만 1차캐시에 있는 값을 줘서 최종적으로 boardEntity값에는 createdTime값이 없는 것으로 이해했습니다. 그런데 왜 open-in-view값을 false로 하면 boardEntity에 createdTime 값이 있는지 모르겠습니다. open-in-view가 true 이건 false 이건 영속성 컨텍스트 생존 범위에 Service는 포함되니 createdTime 값이 둘 다 없어야 되는것이 아닌지 궁금합니다.
-
해결됨코드로 배우는 React with 스프링부트 API서버
[스프링부트 3.2] RefreshToken 발급시 파라미터 오류
스프링부트 3.2 버전인데 APIRefreshController의 refresh의 파라미터중 String refreshToken만 적으면 -parameter 오류가 나네요. 인텔리제이에서 gradle로 빌드하거나 어노테이션에 이름을 붙여 적으니 잘 동작합니다. 식겁했습니다..
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
트랜잭션 관련 질문
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요.현재 컨트롤러에서 직접 리포지토리를 접근하는데 예전 강의에서 단순 엔티티 조회할때는 실용적인 관점으로 서비스를 통해 접근하는 것이 아닌 리포지토리로 바로 접근하기도 한다는걸 들었습니다. 이번 강의에 그 점이 적용이 된거 같습니다.여기서 궁금점은 jpa의 모든 데이터 변경은 트랜잭션 안에서 실행된다고 하셨는데 현재 레포지토리에 바로 접근하면서 @Transactional 애노테이션을 사용안하는 것을 확인하였습니다. 단순 조회에서는 트랜잭션을 시작할 필요가 없는 건가요? 아니면 숨겨진 기능이 있는건지 궁금합니다!
-
해결됨자바 ORM 표준 JPA 프로그래밍 - 기본편
플러시와 persist()에 대해 질문 있습니다.
플러시가 발생하여 쓰기 지연 저장소에 쌓여있던 쿼리들이 DB에 보내지게 되면 쓰기 지연 저장소에 쌓여있던 쿼리들은 삭제되나요 아니면 그대로 남아있나요?pk 생성 전략이 identity일 경우 persist()할때 쓰기 지연 저장소로 가는게 아니라 DB로 바로 보내지고 id 값을 얻어온다고 이해 했습니다. 그러면 persist()할때 생긴 insert into 쿼리가 DB로 보내지는데 이때 커밋하기전이라 DB에는 반영이 안되는건가요? DB 내부에서 버퍼? 같은 곳에서 보관했다가 커밋했을때 insert into 쿼리가 작동되는건지 궁금합니다.
-
미해결자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
14강. 유저 업데이트 API, 삭제 API 개발과 테스트 수정하기 안됨
코드대로 글을 잘 작성하고 POST,GET,DELETE도 전부 잘 동작하고 db에서도 확인이 되는데,수정하기만 동작하지 않습니다..어떻게 해야할까요..수정하기 버튼을 누를시 아무런 화면의 변화가 없습니다.
-
미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
em.clear 후 프록시 초기화 문제
안녕하세요 :)Member refMember = em.getReference(Member.class, member.getId()); em.clear() refMember.getName();이때 LazyInitializationException이 일어나는 것에 대해 질문드립니다.프록시 객체 refMember는 getName()을 호출할 때 최초로 단 한번 초기화되는 것으로 이해했습니다.그렇다면 이전에 em.clear()로 영속성 컨텍스트를 초기화하여도, refMember.getName() 시점에 다시 DB에서 member 엔티티를 찾아 영속성 컨텍스트에 올리면 되지 않나요? refMember는 그 엔티티를 target으로 하고요.왜 예외가 일어나는 것인지 궁금합니다!
-
미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
실전예제 따라쳐야 하나요?
실전 예제 부분 따라쳐야 하나요?다른 강의처럼 소스코드 첨부파일도 없고pdf파일에도 소스코드도 없고따라치라는 말도 없고 그래서 해야하는건지 그냥 눈으로 보기만하라는건지 모르겠네요
-
미해결실전! Querydsl
querydsl 2개의 파일에서 같은 조건을 사용해야 할 경우
강사님 안녕하세요.좋은 강의 잘 들었습니다.querydsl의 정점 중 하나로 where 조건문을 분리하고 재사용한다고 했는데,예를 들어 UserRepository, StudyRepository라는 2개의 querydsl을 사용하는 repository가 있다 했을 때, 각각의 respository 에서 조회를 할 때 동일한 조건을 사용해야 할 경우가 있습니다. UserRepository.javapublic User getUser(Long UserId) { return selectForm(user) .where(userId); } private BooleanExpression eqUser(Long userId) { return user.userId.eq(userId); }StudyRepository.javapublic User getUser(Long UserId) { select(study) .from(study.user, user) .join(study.user) .where(user.userId.eq(UserId)); } private BooleanExpression eqUser(Long userId) { return user.userId.eq(userId); } 이렇게 .where(user.userId.eq(1L)) 가 2개의 파일에서 반복되는 경우 각각의 파일에 메소드로 사용하는게 좋을까요? 아니면 다음처럼 공통 유틸 파일을 만들어서 공통으로 사용하는게 좋을까요?QueryUtils.javapublic static BooleanExpression eqUser(Long userId) { return user.userId.eq(userId); }실무에서는 어떻게 사용 할까요? 이런 경우가 빈번해서 질문 드립니다.
-
미해결코드로 배우는 React with 스프링부트 API서버
ModelMapper 와 entityToDto 차이
강사님의 강의에서 엔티티를 DTO로 변환할때 2가지 방식을 다 보여주셨는데 , 모델 매퍼로 엔티티 -> DTO 변환방식과 entityToDto 메소드 처럼 직접 개발자가 명시해줘서 엔티티를 DTO로 변환하는 방식의 차이점과 선택기준이 궁금합니다!!
-
미해결자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
섹션3 질문 있습니다
안녕하세요!섹션3 마지막 부분쯤 나온 @Component 어노테이션에 대해 질문이 있습니다!이 어노테이션은 다음과 같은 경우에 사용된다고 하셨는데요!컨트롤러, 서지스, 리포지토리가 모두 아니고,개발자가 직접 작성한 클래스를 스프링 빈으로 등록할 때 사용된다. 제가 궁금한 것은 Service 나 리포지토리 모두 우리가 직접 작성한 클래스 아닌가요??그러면 컴포넌트 어노테이션 아닌가요??답변해주시면 감사하겠습니다
-
해결됨입문자를 위한 Spring Boot with Kotlin - 나만의 포트폴리오 사이트 만들기
섹션3 컨트롤러테스트 오류
안녕하세요. 강의노트와 강의를 보면서 수정해 보았는데 resume에서만 test가 실패합니다. 제가 보기엔 resume가 JSON이 null이라서 그런것 같은데 어느 부분을 봐야할지 모르겠습니다. Datainitiallizer.kt를 봐도 잘 안보이네요. 아래는 에러 메세지와 코드입니다.java.lang.NullPointerException: Cannot invoke "org.json.JSONArray.length()" because the return value of "org.json.JSONObject.optJSONArray(String)" is null at com.dogu.portfolio.presentation.controller.PresentationApiControllerTest.testGetResume(PresentationApiControllerTest.kt:66) at java.base/java.lang.reflect.Method.invoke(Method.java:569) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) @Test @DisplayName("resume") fun testGetResume() { //given val uri = "/api/v1/resume" //when val mvcResult = performGet(uri) val contentAsString = mvcResult.response.getContentAsString(StandardCharsets.UTF_8) val jsonObject = JSONObject(contentAsString) //then Assertions.assertThat(jsonObject.optJSONArray("experiences").length()).isPositive() Assertions.assertThat(jsonObject.optJSONArray("achievements").length()).isPositive() Assertions.assertThat(jsonObject.optJSONArray("skills").length()).isPositive() }
-
해결됨자바 ORM 표준 JPA 프로그래밍 - 기본편
교재 내용중에 질문 있습니다.
교재 내용중에 아래와 같은 내용이 있습니다."데이터가 변해도 식별자로 지속해서 추적 가능회원 엔티티의 키나 나이값을 변경해도 식별자로 인식가능"여기서 궁금한 부분이 회원 엔티티의 키가 식별자라고 생각하는데 여기서 키가 바뀌게 되면 식별자도 바뀌게 되어 추적이 불가능하지 않나요?
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
join과 join feth 차이점
public List<Order> findSearchOrders(OrderSearch orderSearch){ return em.createQuery("select o from Order o join o.member m" + " where o.orderStatus = :status" + " and m.name like :name", Order.class) .setParameter("status", orderSearch.getOrderStatus() ) .setParameter("name", orderSearch.getMemberName()) .setMaxResults(1000) .getResultList(); } public List<OrderQueryDto> findQueryOrder() { List<OrderQueryDto> result = findAllOrder(); for (OrderQueryDto order : result) { List<OrderItemQueryDto> orderItems = findOrderItem(order.getId()); order.setOrderItems(orderItems); } return result; } public List<OrderItemQueryDto> findOrderItem(Long orderId) { String query = "select new jpabook.jpashop.repository.order.query." + " OrderItemQueryDto(oi.order.id, oi.orderPrice, oi.count )" + " from OrderItem oi " + " join oi.item i" + " where oi.order.id = :orderId"; return em.createQuery(query,OrderItemQueryDto.class) .setParameter("orderId", orderId) .getResultList(); } public List<OrderQueryDto> findAllOrder(){ String query = "select new jpabook.jpashop.repository.order.query." + " OrderQueryDto(o.id, m.name, d.address, o.orderStatus, o.orderDate) " + " from Order o " + " join o.member m" + " join o.delivery d"; return em.createQuery(query, OrderQueryDto.class).getResultList(); }첫번째 코드 블럭은 order를 select 할때 member를 join 하면 member를 프록시 객체로 가져오는걸로 알고 있습니다. join fetch 를 하게 되면 바로 객체로 가지고 오는걸로 알고 있습니다. 하지만, 두번째 코드 블럭은 그냥 join을 했는데, 왜 프록시 객체에서 객체로 전환? 프록시 객체가 객체를 가르키는 행위를 하지않고도 dto에 바로 삽입이 가능한가요?ex) order.getName() , member.getName()
-
해결됨자바 ORM 표준 JPA 프로그래밍 - 기본편
CascadeType.ALL, CascadeType.REMOVE 옵션에 대해 질문 있습니다.
부모를 삭제 시에는 CascadeType.ALL과 CascadeType.REMOVE가 똑같이 동작한다고 이해해서 이 둘에 대해 동시에 질문 하겠습니다.만약에 하나의 게시글이 있고 이 게시글에 달려있는 첨부파일들이 100개 라고 하겠습니다.이때 CascadeType.ALL 옵션을 사용하면 게시글 삭제 시 100개의 첨부파일들도 삭제 된다고 이해를 했습니다.궁굼한 부분은 게시글 삭제 시 게시글에 달린 100개의 첨부파일에 대해 delete 쿼리가 따로 따로 보내지는건지 아니면 jpa가 최적화 해서 한번에 보내는건지 궁금합니다.만약에 1번 질문에서 Jpa가 알아서 최적화해서 delete 쿼리를 DB로 보낸다고 가정하겠습니다. 그러면 100개의 첨부파일에 대한 Id 값을 다 뽑아서 이 값들을 delete 쿼리의 where절의 in에 넣어서 삭제 쿼리를 보내는것 대신에 Jpa가 최적화 해서 delete 쿼리를 보내는 방식이 더 좋은지 궁금합니다.
-
미해결자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
26강 오류입니다 !
Execution failed for task ':LibraryAppApplication.main()'.> Process 'command 'C:/Program Files/Java/jdk-11/bin/java.exe'' finished with non-zero exit value 1 이것은 어떤 에러일까요 ㅠㅠ
-
미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
@MappedSuperclass 공통속성 자동화
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]Mapped Superclass- 매핑 정보 상속 6:44 부분에 말씀하신 작성자, 작성일, 수정자, 수정일을 자동화하는 jpa 기능이 있다고 말씀 해주셨는데말씀 하신 건만 듣고는 이해가 안되서요자동화 시키는 걸 쉽게 할 수 있는 방법이 있는 건가요?바로 적용해보고 싶어서요
-
해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
비즈니스로직 처리 위치
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]지금까지 컨트롤러단에서 로직을 다 작성하셨는데요원래 비즈니스로직 같은 경우는 서비스 단에서 처리를 해야 되지 않나 생각이 들어 질문합니다.간단한 예시여서 컨트롤러 단에서 로직을 처리하고 dto를 이너클래스로 만드신 건가요?비즈니스로직 처리 위치를 컨트롤러에서 해야될지 서비스단에서 해야될지 기준이 잘안서서 질문드립니다.~~
-
미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
쿠버네티스 버전에서의 토큰 검사
안녕하세요, 강의 잘 들었습니다.기존에 로그인 후 발급한 토큰을 apigateway에서 검사했었는데 k8s 버전에서는 별도로 토큰을 검사하지 않는 것 같습니다. 로그인하는 의미가 없어질 것 같은데 이부분을 추가하려면 각 서비스에 따로 추가를 하는게 좋을까요?아니면 중앙으로 처리하는 방법이 따로 있을까요?
-
해결됨실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
'회원 이름 필수 입력' 기능
안녕하세요. 웹계층 회원등록 부분 강의 따라서 코딩하고, HTML 파일도 복붙했는데홈페이지에 이름을 입력 안 해도 '회원 이름을 필수입니다' 메세지가 뜨는 반응이 없이 redirect됩니다. h2에는 이름이 비어 있는 상태로 데이터가 들어와 있습니다. @NotEmpty가 왜 작동하지 않는지 질문드립니다. https://drive.google.com/file/d/1jvu4wiWz3GwoZ3YazNDJWsFTOxgSqt-M/view?usp=sharing
-
미해결스프링 DB 2편 - 데이터 접근 활용 기술
readonly 트랜잭션에 update를 수행하는 분리된 트랜잭션 메서드를 호출 할 때 질문
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)예3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)예[질문 내용]안녕하세요 영한님이번에 트랜잭션 적용하면서 @Transactional(readOnly = true) 가 붙은 조회 메서드 내부에 @Transactional(propagation = Propagation.REQUIRES_NEW)가 붙은 외부 클래스의 메서드가 사용 될 때물리 트랜잭션이 분리되었고 각각 다른 트랜잭션임에도변경감지가 적용안되는 부분이 궁금했습니다.아래는 궁금한 부분에 대한 테스트를 진행한 코드입니다. @Service @RequiredArgsConstructor public class TeamService { private final TeamRepository teamRepository; private final TeamExternalService externalService; @Transactional(readOnly = true) public Team findTeamWithNameChangeExternal(Team team, String name) { Team findTeam = teamRepository.findByName(team.getName()); externalService.changeName(findTeam, name); return findTeam; } } @Service @RequiredArgsConstructor public class TeamExternalService { @Transactional(propagation = Propagation.REQUIRES_NEW) public void changeName(Team findTeam, String name) { findTeam.setName(name); } } @Test void findTeamWithNameChangeExternal() { Team team = new Team("team"); Team savedTeam = teamRepository.save(team); teamService.findTeamWithNameChangeExternal(savedTeam, "changeName"); Team findTeam = teamRepository.findByName("changeName"); assertThat(findTeam.getName()).isEqualTo("changeName"); }같은 클래스에서 내부 호출 할 경우에는 REQUIRES_NEW를 적용하더라도 같은 프록시 객체로 해당 메서드가 호출된 상위 트랜잭션의 옵션을 그대로 따라 가기 때문에 변경 감지가 적용안된다고 생각했어요 하지만 이와 다른 외부 클래스의 분리된 트랜잭션에서는 변경 감지가 일어나는 것이 정상이라고 생각했는데왜 변경 감지가 일어나지 않는 것일 까요 ..? 아래는 궁금해서 디버그를 찍어봤어요보니가 두 트랜잭션의 번호가 Transaction@13592로 같고 REQUIRES_NEW가 적용된 트랜잭션의 경우에는 oldTrasactionInfo 이라는 정보를 갖고 해당 메서드를 실행하는 @Transactional(readOnly = true)옵션이 적혀있더라구요 ??그렇다면 내부 호출이 아닌 외부 호출이라도readOnly = true로 조회 성능을 챙기면서 변경 감지를 사용할 순 없는 것인가요 ??