안녕하세요, 무한 스크롤 방식에서 페이지 번호 방식 쿼리의 문제점을 설명한 부분에 질문이 있습니다. 페이지 방식을 무한 스크롤 방식에 적용 시 문제점으로 아래 2가지를 제시하셨는데요, 1) 페이지가 추가된 경우, 데이터 중복 조회 문제 2) 페이지가 삭제된 경우, 데이터 누락 문제 궁금한 점은, 이러한 문제는 무한 스크롤에서 사용했을 때 뿐 아니라, 페이지 번호 방식을 사용할 때도 마찬가지로 문제가 있는 것 아닌가 싶다는 것입니다. 페이지 번호 방식 자체의 한계라고 생각하는데, 페이지 번호 방식에서는 발생하지 않는 문제인가요?
안녕하세요. 싱글톤 관련 질문 드립니다. 특정한 의문점에 대한 질문은 아니고요. 스프링 컨테이너는 핸들러나 서비스 빈을 싱글톤으로 관리하게 되는데, 혹시 강의에서 등장한 자바와 코틀린의 싱글톤 사용 방식의 차이에 의해 발생하는 스프링 싱글톤 관련된 이슈가 있는지 궁금합니다. 싱글톤 관리는 언어와 관계없이 스프링 컨테이너가 맡게 되니 별 상관이 없을 것으로 예상되긴 합니다만.. 혹시 싶어 질문 드립니다. 감사합니다.
먼저, 이렇게 양질의 강의 올려주셔서 정말 감사드립니다. 잘 듣고 있습니다. 49강의 실습에서 equals 메소드를 재정의한다고 말씀하셨습니다. 그런데, MyString 은 Object 로부터 equals(Object) 를 상속 받았고, 강의에서 보여주신 코드에서는 equals(MySring) 을 정의했으므로, 메소드 시그니처가 달라 재정의(overriding)보다는 overloading이 더 적절한 표현이 아닌가 싶어서 질문드립니다. 실제로 인텔리제이에서 equals(MyString) 에 @Override 어노테이션을 붙이려하면 아래의 사진과 같은 오류가 발생합니다. 아니면 제가 재정의에 대해서 오해하고 있는 부분이 있는걸까요?
안녕하세요! 수업 잘 듣고 있습니다. 사소한 내용이긴한데.. OrderService.create 에서 OrderKeyGenerator 객체를 를 주입받아 generate() 를 호출해서 orderKey 를 생성하는 부분에서 OrderKeyGenerator class 는 상태를 가지지도 않고 Property 를 가지지도 않는데 static method, 함수로 구현 되어도 되지 않았을까 하는 생각이 들었는데요. 어떤 고려사항이 있는지 궁금합니다. static 이든 함수든 객체 메서드이든 상관 없다? 나중에 OrderKeyGenerator 가 확장되는 것이 고려된 것? OrderSerivce 에서 사용하는 기능이니 주입되는 것이 더 응집되어 보여서 더 좋다? 그냥 함수를 가져다 쓰는 것보다 객체를 주입하는 쪽이 테스트 하기 좋다? generate 가 순수함수가 아니라서? class OrderKeyGenerator { fun generate(): String { return Base64.getUrlEncoder().withoutPadding().encodeToString( ByteBuffer.allocate(16).apply { UUID.randomUUID().also { putLong(it.mostSignificantBits) putLong(it.leastSignificantBits) } }.array(), ) } }
강사님 강의 재밌게 너무 잘 보고있습니다!!! 클로드 코드에 대해서도 사용해보니까.. 재밌어요 PostgreSQL을 왜 선택하고 특징, 장점까지 잘 보았습니다. 하지만 MySQL에 유리한 프로젝트는 무엇인지 궁금합니다. PostgreSQL선택한 이유중에 부분 인덱스 지원해주고 JSON을 효율적으로 저장할 수 있는 타입인 JSONB도 지원해주고 커뮤니티도 풍부하고 READ COMMITTED - 높은 읽기 성능을 제공해주는것으로 MySQL보다 전부 뛰어나다고 생각이듭니다. MySQL과 차이점은 MySQL은 Reapeatable Read로 정합성을 챙기고 MVCC덕분에 높은 읽기 성능을 가지고 있는걸로 알고있습니다. 그 외에 MySQL의 장점과 유리한 프로젝트들 예시를 좀 조언을 얻고싶습니다
안녕하세요. 강의를 듣던 중 생성자 호출 결과와 관련해 궁금한 점이 생겨 질문드립니다. 해당 예제에서 new 연산자 사용 시 다중 정의된 int 타입 파라미터를 받는 생성자가 호출된다고 설명해 주셨는데, 그 이유가 궁금합니다. new 연산자에 int 타입 매개변수를 전달한 상황을 가정하고 설명하신 것일까요? 강의와 유튜브 항상 잘 보고 있습니다. 감사합니 다.
안녕하세요. 상속과 별로 연관된 질문은 아닌 듯 하지만 강의에서 나온 부분에 궁금증이 생겨 질문 남깁니다. val swimAbility: Int get() = 3 이라는 예제 코드를 작성하셨는데요. 코틀린은 어차피 필드를 선언하면 게터, 세터를 만들어주고 필드 선언 시 디폴트 값도 지정해줄 수 있는데 그렇다면 위와 같은 형태의 커스텀 게터는 굳이 구현할 필요 없는 것 아닌가? 하는 생각이 듭니다. 그냥 초기값 3을 갖는 필드를 선언하기만 하면 게터까지 알아서 만들어질 테니까요. 그냥 인터페이스의 게터 상속 의도를 표현하기 위해 별 의미나 실 용례는 없는 코드를 작성하신 거라고 봐도 될지? 아니면 저런 방식의 커스텀 게터에 제가 이해하지 못하는 어떤 의미가 있는 것일지가 궁금합니다. 감사합니다. ㅇ
수업 챕터 14. 세션 로그인 ▶ ︎ 구현과 동작 에서 6분 35초쯤에 Docker 에서 Redis Container 로 진입하시고 /data # redis-cli 명령을 작성하실 때, 원래는 이런 명령어를 사용하시면 안된다고 하시는데 그럼 원래는 무슨 명령어를 사용하는지 궁금하네요
자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
@PutMapping("/user") public void updateUser(@RequestBody UserUpdateRequest request){ String readSql = "select * from user where id=?"; String sql = "update user set name=? where id=?"; jdbcTemplate.update(sql, request.getName(), request.getId()); } 웹페이지에서 update를 발생시켜서 put 요청이 올라 왔을때 UserUpdateRequest dto에 id와 name이 들어 간다는건 웹에서 요청이 올라왔을때 json에 이미 해당 name에 대한 id 정보가 있다는 거죠? id는 db에서 자동적으로 생성해 준다고 했었는데, 이 id를 웹에서는 어떻게 알고 있나요?
1. 현재 학습 진도 몇 챕터/몇 강을 수강 중이신가요? 4-8강 2. 어려움을 겪는 부분 어느 부분에서 막히셨나요? chapter4/_2_event_with_participant 폴더의 EventJoinService 객체의 메서드 코드에 대한 질문입니다. 코드의 어떤 로직이 이해가 안 되시나요? @Transactional public void joinEvent(Long eventId, Long memberId) { Event event = eventRepository.findById(eventId) .orElseThrow(() -> new EntityNotFoundException("이벤트를 찾을 수 없습니다.")); Member member = memberRepository.findById(memberId) .orElseThrow(() -> new EntityNotFoundException("회원을 찾을 수 없습니다.")); // save()를 호출하지 않아도 Dirty Checking에 의해 Update 쿼리가 나가지 않나요? event.increaseParticipants(); eventRepository.save(event); EventParticipant participant = EventParticipant.builder() .event(event) .member(member) .build(); participantRepository.save(participant); } } 코드 블럭의 주석 란에 질문을 적어놓았습니다. 저 상황에서 save() 를 호출하는 이유가 궁금합니다. JPA 엔티티의 상태 변경분에 대한 쿼리는 트랜잭션 커밋 후, 자동으로 나가는 것으로 알고 있습니다. 혹시, 제가 잘못 알고 있는건지 궁금합니다.
안녕하세요 토비님!! 강의를 완강하고 제 프로젝트를 리팩토링하면서 피드백받고싶은점이 생겨 질문글을 올립니다. Repository Port를 기술에 종속시키지 않기 위해 Adapter에서 JPA, MyBatis, QueryDSL을 조합하는 구조를 선택했는데, 이 설계 방향이 적절한지 조언을 구하고 싶습니다. 현재 구조 core/ └── domain/ └── application/ └── required/ ← Port 인터페이스 └── ~Repository adapter/ └── persistence/ ├── ~RepositoryAdapter ← Port 구현체 ├── ~JpaRepository ← Spring Data JPA └── ~MybatisMapper ← Mybatis 매퍼 인터페이스 의존 관계 [Service] → [Repository] ←impl― [RepositoryAdapter] → [JpaRepository] → [MybatisMapper] → [JPAQueryFactory] (core) (core) (adapter) (adapter) 예시 @Repository @RequiredArgsConstructor public class ItemRepositoryAdapter implements ItemRepository { private final ItemJpaRepository itemJpaRepository; private final ItemMybatisMapper itemMybatisMapper; @Override public List<Item> findBySearchRequest(ItemSearchRequest request) { return itemMybatisMapper.findBySearchRequest(request) .stream() .map(Item::from) .toList(); } @Override public List<Item> saveAll(List<Item> items) { return itemJpaRepository.saveAll(items); } } @Repository @RequiredArgsConstructor public class AuctionRepositoryAdapter implements AuctionRepository { private final JPAQueryFactory jpaQueryFactory; private final AuctionJpaRepository auctionJpaRepository; @Override public void deleteAllByRegionAndRealmId(RegionType region, Long realmId) { QAuction qAuction = QAuction.auction; BooleanBuilder filter = new BooleanBuilder(); filter.and(qAuction.region.eq(region)); if (realmId == null) { filter.and(qAuction.realmId.isNull()); } else { filter.and(qAuction.realmId.eq(realmId)); } jpaQueryFactory.delete(qAuction) .where(filter) .execute(); } @Override public int saveAll(List<Auction> auctions) { if (auctions.isEmpty()) return 0; return auctionJpaRepository.saveAll(auctions).size(); } } 이 구조를 선택한 이유 동적 쿼리, 벌크 연산 등 JPA만으로 해결하기 어려운 케이스가 있어 MyBatis와 QueryDSL을 병행 사용하고 있습니다. 일반적인 방식인 Port 인터페이스가 Spring Data JPA Repository를 상속하는 구조를 채택하지 않은 이유: MyBatis나 QueryDSL 기반 구현체를 만들 수 없음 CustomRepository 인터페이스를 별도로 만들어야 하는 복잡도 증가 현재 방식의 장점: Port 인터페이스가 순수 Java 인터페이스로 유지됨 RepositoryAdapter에서 상황에 맞는 기술을 자유롭게 조합 가능 추가 인터페이스 없이 단순한 구조 유지 저는 현재 구조가 의존 관계도 외부에서 내부로 향하고 테스트도 쉬워서 괜찮다고 생각하는데 토비님의 생각도 듣고싶습니다!! 좋은 강의 감사합니다!!
안녕하세요, 강사님덕분에 많이 배웁니다. 공부하면서 궁금한 내용이 있어 질문드립니다. FK 값 중복은 괜찮은거지? - 예시 규칙 1의 products(판매 상품) 가게 id(FK) 값 규칙 3 내용 중, 서비스를 중심으로 동사(팔다)를 골라 엔티티간 관계를 설정할 때 예시 2 내용입니다. 가게(stores), 판매상품(products) - 하나의 가계는 여러 개의 상품을 판다(팔수있다) 여기까지 이해를 했는데, 판매상품과 가게 관계에서 왜 '하나의 상품' 이라는 표현을 하는건가요? 여러개의 상품을 판다. 라고 벌써 정의 했으면서, 왜 하나의 상품이라고 하지? 여러개의 상품은 하나의 가게에 의해 팔린다. 라고 해야 하지 않나? 그래서 1:N 관계가 되는거 아니야? 그런 생각에 질의 드렸습니다. 감사합니다ㅡ
안녕하세요, 강사님. 이번 강의를 듣고 2가지 궁금증이 생겨 질문을 올리게 되었습니다. created_at 과 updated_at 구현 DB 레벨에서 ON UPDATE 와 DEFAULT CURRENT_TIMESTAMP 를 활용할 수 있다고 말씀해 주셨는데요, JPA에서는 @CreatedDate 와 @LastModifiedDate 로 애플리케이션 단에서 이를 구현할 수도 있습니다. 실무에서는 각각을 언제 사용할까요? 그리고 권장하는 구현이 따로 있으실까요? DB ENUM 타입을 잘 사용하지 않는 이유 실무에서 DB ENUM 데이터 타입 사용을 권장하지 않는다는 말씀으로 이해했습니다. 단순히 해당 ENUM 값의 범위가 변경되었을 때 이를 바꿔주는 것 이상으로 성능 이슈가 있어서라고 생각했습니다만, 정확히 알기가 어렵습니다. 자세한 설명을 부탁드려도 될까요? 감사합니다.
이런 식으로 실무적으로 접근했을 때 이 강의에서 예시를 들어주셨던 것처럼 (학생, 과목, 수강), (사용자, 영화, 평가) 엔티티를 개념적 모델링 단계에서 먼저 설계를 할텐데, 이때 설계 순서가 궁금합니다. (학생, 과목), (사용자, 영화) 와 같은 기본 엔티티를 먼저 만든 다음에 M:N 다대다 관계인 것을 확인하고 이것을 풀어내면서 동시에 비즈니스적 의미를 넣기 위해 중심(연관) 엔티티를 만드는 게 일반적인가요? 아니면 처음부터 학생 -> 수강 -> 과목 or 사용자 -> 평가 -> 영화 로 이어지도록 설계하는 게 일반적인가요?
package hellojpa; import javax.persistence.Entity; import javax.persistence.Id; @Entity public class Member { @Id private Long id; private String name; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } package hellojpa; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; public class JpaMain { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); tx.begin(); Member member = new Member(); member.setId(1L); member.setName("HelloA"); em.persist(member); tx.commit(); em.close(); emf.close(); } } C:\Users\User\.jdks\temurin-21.0.9\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2025.2.2\lib\idea_rt.jar=65054" -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 -classpath C:\study\ex1-hello-jpa\ex1-hello-jpa\target\classes;C:\Users\User\.m2\repository\javax\xml\bind\jaxb-api\2.3.0\jaxb-api-2.3.0.jar;C:\Users\User\.m2\repository\org\hibernate\hibernate-entitymanager\ 5.3.10.Final \ hibernate-entitymanager-5.3.10.Final .jar;C:\Users\User\.m2\repository\org\jboss\logging\jboss-logging\ 3.3.2.Final \ jboss-logging-3.3.2.Final .jar;C:\Users\User\.m2\repository\org\hibernate\hibernate-core\ 5.3.10.Final \ hibernate-core-5.3.10.Final .jar;C:\Users\User\.m2\repository\org\javassist\javassist\3.23.2-GA\javassist-3.23.2-GA.jar;C:\Users\User\.m2\repository\antlr\antlr\2.7.7\antlr-2.7.7.jar;C:\Users\User\.m2\repository\org\jboss\jandex\ 2.0.5.Final \ jandex-2.0.5.Final .jar;C:\Users\User\.m2\repository\com\fasterxml\classmate\1.3.4\classmate-1.3.4.jar;C:\Users\User\.m2\repository\javax\activation\javax.activation-api\1.2.0\javax.activation-api-1.2.0.jar;C:\Users\User\.m2\repository\org\dom4j\dom4j\2.1.1\dom4j-2.1.1.jar;C:\Users\User\.m2\repository\org\hibernate\common\hibernate-commons-annotations\ 5.0.4.Final \ hibernate-commons-annotations-5.0.4.Final .jar;C:\Users\User\.m2\repository\javax\persistence\javax.persistence-api\2.2\javax.persistence-api-2.2.jar;C:\Users\User\.m2\repository\net\bytebuddy\byte-buddy\1.9.5\byte-buddy-1.9.5.jar;C:\Users\User\.m2\repository\org\jboss\spec\javax\transaction\jboss-transaction-api_1.2_spec\ 1.1.1.Final \jboss-transaction-api_1.2_ spec-1.1.1.Final .jar;C:\Users\User\.m2\repository\com\h2database\h2\1.4.199\h2-1.4.199.jar hellojpa.JpaMain 1월 13, 2026 3:42:37 오후 org.hibernate.jpa.internal.util.LogHelper logPersistenceUnitInformation INFO: HHH000204: Processing PersistenceUnitInfo [ name: hello ...] 1월 13, 2026 3:42:37 오후 org.hibernate.Version logVersion INFO: HHH000412: Hibernate Core { 5.3.10.Final } 1월 13, 2026 3:42:37 오후 org.hibernate.cfg.Environment <clinit> INFO: HHH000206: hibernate.properties not found 1월 13, 2026 3:42:37 오후 org.hibernate.annotations.common.reflection.java .JavaReflectionManager <clinit> INFO: HCANN000001: Hibernate Commons Annotations { 5.0.4.Final } 1월 13, 2026 3:42:38 오후 org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator initiateService WARN: HHH000181: No appropriate connection provider encountered, assuming application will be supplying connections 1월 13, 2026 3:42:38 오후 org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator initiateService WARN: HHH000342: Could not obtain connection to query metadata : The application must supply JDBC connections 1월 13, 2026 3:42:38 오후 org.hibernate.dialect.Dialect <init> INFO: HHH000400: Using dialect: org.hibernate.dialect.H2Dialect 1월 13, 2026 3:42:38 오후 org.hibernate.engine.jdbc.env.internal.LobCreatorBuilderImpl makeLobCreatorBuilder INFO: HHH000422: Disabling contextual LOB creation as connection was null Exception in thread "main" java.lang.UnsupportedOperationException: The application must supply JDBC connections at org.hibernate.engine.jdbc.connections.internal.UserSuppliedConnectionProviderImpl.getConnection(UserSuppliedConnectionProviderImpl.java:44) at org.hibernate.internal.NonContextualJdbcConnectionAccess.obtainConnection(NonContextualJdbcConnectionAccess.java:35) at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.acquireConnectionIfNeeded(LogicalConnectionManagedImpl.java:106) at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getPhysicalConnection(LogicalConnectionManagedImpl.java:136) at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getConnectionForTransactionManagement(LogicalConnectionManagedImpl.java:254) at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.begin(LogicalConnectionManagedImpl.java:262) at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.begin(JdbcResourceLocalTransactionCoordinatorImpl.java:236) at org.hibernate.engine.transaction.internal.TransactionImpl.begin(TransactionImpl.java:86) at hellojpa.JpaMain.main(JpaMain.java:16) Process finished with exit code 1 이거 에러 발생한 이유가 뭘까요? 강의 러닝타임은 11분대입니다.