스프링 데이터 JPA
스프링 데이터 JPA
수강정보
(88개의 수강평)
1533명의 수강생
스킬태그 #Java, #Spring, #Spring Data JPA
5개월 할부시
월 17,600원88,000원
지식공유자 : 백기선
45회 수업 · 총 9시간 22분 수업
기간 : 평생 무제한 시청
수료증 : 발급 강의
수강 난이도 : 중급이상
jihuni1026 프로필

안녕하세요. 질문 드립니다. jihuni1026 10일 전
안녕하세요.  단방향으로 설정시 관계 테이블이 보이고, 양방향 설정시 관계 테이블이 보이지 않습니다. 이게 정상인건가요? 제가 제대로 했는지 의심이 들어서 질문드립니다. [단방향]  Schema |      Name      | Type  |   Owner --------+----------------+-------+------------  public | course         | table | jihuni1026  public | member         | table | jihuni1026  public | member_courses | table | jihuni1026 [양방향]  Schema |      Name      | Type  |   Owner --------+----------------+-------+------------  public | course         | table | jihuni1026  public | member         | table | jihuni1026

1
Tae-Nam Kim 프로필

특정 repository를 이용해 save 후 DB에도 반영된 정보가 해당 repository 를 통해 find 시 DB반영된 정보를 가지고 오지 못하는 현상에 대한 질문드립니다. Tae-Nam Kim 19일 전
아래와 같은 소스들이 있습니다. 1. 인터페이스기반의 repository public interface TestModelRepository extends JpaRepository<TestModel, Long>{ } 2. 서비스 @Service public class TestService { ... @Autowired TestModelRepository testModelRepository; public void test() { ... while(true) { Optional<TestModel> optTestModel = testModelRepository.findById(id); TestModel testModel; if(optTestModel.isPresent()) { testModel = optTestModel.get(); logger.info("testModel: {}", testModel.toString()); } } } ... } 3. worker thread를 통해 호출되는 코드 public class TestAction { ... public void act(TestModelRepository testModelRepository, TestModel testModel) { ... testModel.setComment("new comment"); TestModel savedTestModel = testModelRepository.save(testModel); logger.info("savedTestModel: {}", savedTestModel.toString()); } ... } 상태 TestService의 test()에 의해 다른 worker thread에서 동작하는 TestAction의 act()가 호출됩니다. TestAction.act에 전달된 testModelRepository는 TestService의 것과 동일한 레퍼런스입니다. TestAction.act()에 의해 정상적으로 DB에 저장된 것이 확인됩니다. 그런데, TestService의 test()에서 주기적으로 TestAction.act()호출 시에 전달한 testModel에 대한 id를 이용해서 `testModelRepository.findById(id)` 를 수행하면 저장된 값이 아닌 저장 이전의 값만 가지고 오고 있습니다. 질문(이해가되지 않는 부분) 위 상태 1.에 의해 저장에 의해 SimpleJpaRepository의 save()의 처리를 타면서 저장한 정보가 merge되었기 때문에 Persistence Context에 정상적으로 적용이 될 것이기 때문에 상태 3의 `testModelRepository.findById(id)` 코드를 통해 해당 entity를 가져오면 정상적으로 변경된 내용을 가지고 와야 할 것 같은데 이해가 되지 않습니다.(제가 Persistence Context관련하여 놓치고 있는 부분이 있는 것 같은데 잘 모르겠네요.) 왜 그럴까요?

6
여섯포반장 프로필

영속성 컨텍스트에 의해 관리되는 entity 확인 시 오작동 문의 여섯포반장 1달 전
안녕하세요. 제가 멀 잘못 했길래 아래 결과가 모두 false 가 나오는거죠? (2.Result : true 가 나와야 한다고 생각 합니다.) (Tester를 만들어  돌리는게 익숙치 않아 직접 돌렸습니다.) 소스는 test05() 수행 해서  Post table에 저장하고, 영속성컨텍스트에 관리 되는 Entity 가 어떤건지 확인 하는 코드 입니다. package com.example.JPA03;import com.example.JPA03.domain.Post;import com.example.JPA03.repository.PostRepository;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.ApplicationArguments;import org.springframework.boot.ApplicationRunner;import org.springframework.data.domain.Sort;import org.springframework.stereotype.Component;import javax.persistence.EntityManager;import javax.persistence.PersistenceContext;import javax.transaction.Transactional;import java.util.Date;import java.util.List;import java.util.Optional;@Componentpublic class JPA03Runner implements ApplicationRunner { @Autowired PostRepository postRepository; @PersistenceContext private EntityManager entityManager; @Override public void run(ApplicationArguments args) throws Exception { test05(); } @Transactional private void test05(){ Post post = new Post(); post.setTitle("ys.."); Post savedPost = postRepository.save(post); // persist System.out.println("1. result : " + entityManager.contains(post) ); System.out.println("2. result : " + entityManager.contains(savedPost) ); }} package com.example.JPA03.domain;import com.example.JPA03.event.PostPublishedEvent;import org.springframework.data.domain.AbstractAggregateRoot;import javax.persistence.*;import java.util.Date;@Entity//@NamedQuery(name="Post.testNamedQuery", query = "select * from Post as p where p.title = ?1")public class Post extends AbstractAggregateRoot<Post> { @Id @GeneratedValue private Long id; private String title; private Integer likeCount; @Temporal(TemporalType.TIMESTAMP) private Date creatDate; public Post publishPostEvent(){ this.registerEvent(new PostPublishedEvent(this)); return this; } public Integer getLikeCount() { return likeCount; } public void setLikeCount(Integer likeCount) { this.likeCount = likeCount; } public Date getCreatDate() { return creatDate; } public void setCreatDate(Date creatDate) { this.creatDate = creatDate; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; }} package com.example.JPA03;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class Jpa03Application { public static void main(String[] args) { SpringApplication.run(Jpa03Application.class, args); }} ==수행 결과 ==   .   ____          _            __ _ _  /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \  \\/  ___)| |_)| | | | | || (_| |  ) ) ) )   '  |____| .__|_| |_|_| |_\__, | / / / /  =========|_|==============|___/=/_/_/_/  :: Spring Boot ::        (v2.3.3.RELEASE) 2020-08-26 01:05:37.745  INFO 4260 --- [           main] com.example.JPA03.Jpa03Application       : Starting Jpa03Application on DESKTOP-GOQMQQP with PID 4260 (D:\private\study\jpa_study\JPA03\target\classes started by BISTel in D:\private\study\jpa_study) 2020-08-26 01:05:37.748  INFO 4260 --- [           main] com.example.JPA03.Jpa03Application       : No active profile set, falling back to default profiles: default 2020-08-26 01:05:38.147  INFO 4260 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFERRED mode. 2020-08-26 01:05:38.208  INFO 4260 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 52ms. Found 1 JPA repository interfaces. 2020-08-26 01:05:38.563  INFO 4260 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor' 2020-08-26 01:05:38.597  INFO 4260 --- [         task-1] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default] 2020-08-26 01:05:38.639  INFO 4260 --- [         task-1] org.hibernate.Version                    : HHH000412: Hibernate ORM core version 5.4.20.Final 2020-08-26 01:05:38.662  INFO 4260 --- [           main] DeferredRepositoryInitializationListener : Triggering deferred initialization of Spring Data repositories… 2020-08-26 01:05:38.749  INFO 4260 --- [         task-1] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.1.0.Final} 2020-08-26 01:05:39.206  INFO 4260 --- [         task-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting... 2020-08-26 01:05:39.296  INFO 4260 --- [         task-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed. 2020-08-26 01:05:39.324  INFO 4260 --- [         task-1] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.PostgreSQL10Dialect 2020-08-26 01:05:39.857  INFO 4260 --- [         task-1] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform] 2020-08-26 01:05:39.862  INFO 4260 --- [         task-1] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default' 2020-08-26 01:05:40.110  INFO 4260 --- [           main] DeferredRepositoryInitializationListener : Spring Data repositories initialized! 2020-08-26 01:05:40.115  INFO 4260 --- [           main] com.example.JPA03.Jpa03Application       : Started Jpa03Application in 2.661 seconds (JVM running for 3.051) Hibernate:      select         nextval ('hibernate_sequence') Hibernate:      insert      into         post         (creat_date, like_count, title, id)      values         (?, ?, ?, ?) 2020-08-26 01:05:41.837 TRACE 4260 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [TIMESTAMP] - [null] 2020-08-26 01:05:41.837 TRACE 4260 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [INTEGER] - [null] 2020-08-26 01:05:41.838 TRACE 4260 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [3] as [VARCHAR] - [ys..] 2020-08-26 01:05:41.838 TRACE 4260 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [4] as [BIGINT] - [66] 1. result : false 2. result : false ㅇㅇ

3
여섯포반장 프로필

insert -> select 와 update-> select 의 동작 차이가 이해가 안됩니다. 여섯포반장 1달 전
안녕하세요 계속 질문을 드르게 되네요. PostRepository 안에 a() 와 b() 라는 메소드를 두개 만들고, a() 메소드는  아래와 같이 save 한후, findById() 로 찾는것 입니다. Insert 쿼리와 select 쿼리가 모두 수행 됐습니다. ==a() 메소드 코드== @Transactionalprivate void test04(){ System.out.println("-------------- test 04 시작 ---------------"); Post post = new Post(); post.setTitle("test_04"); post.setLikeCount(1); post.setCreatDate(new Date()); Post savedPost = postRepository.save(post); Optional<Post> findPost = postRepository.findById(savedPost.getId()); System.out.println("Result====>"+ findPost.get().getTitle() );} ==수행결과== b() 메소드를  "스프링 데이타 JPA6 update쿼리 " 챕터에서 말씀 하신것처럼 만들면, 강의 하실때 말씀 하시길 update() <- (직접만든것은 권장안함) 수행 후 에 findById() 로 조회를 하게 되면,  PersistenceContext 에 영속성으로 들어가 있어서 불필요한 쿼리 라고 생각 해서 update 만 수행 되고 select 쿼리는 수행 안된다고 하셨습니다. 왜 a() 와 b() 메소드가 서로 수행이 왜 틀린거죠? a() 메소드 역시 영속성 컨테이너에는  db에 저장한 내용이 남아 있으니, findByid 시에 쿼리를 날리지 않아도 되지 않나요? 지연 쿼리이고, 싱크를 맞추기 위해  findById() 수행 시점에  Insert 쿼리와 select 쿼리가 날라 간다고 여러 차례 말씀 하셨는데요 a() 와 b() 메소드 모두 db 작업을 했고,  db 작업 후에 findById()를 하는것인데 insert 문은 수행한 a() 는  싱크를 맞추기 위해  select문을 수행하고 update문을 수행한 b()는 싱크를 맞추지 않고 영속성 context에서 가져오는 이유를  모르겠습니다.

2
여섯포반장 프로필

커스텀 리파지토리 만들기 질문 입니다. 여섯포반장 1달 전
안녕 하세요 계속 질문을 드리게 되네요. 코딩 하시는거 보니,  저는 지금까지 프로그래머도 아니고 그냥 코더 였네요. 스프링 데이터 Common 7. 커스텀 리포지토리 만들기 Chatper 보고 드리는 질문 입니다. 강의에 아래와 같이 나옵니다. 1. PostCustomRepository 란 Interface 만든다.      해당 Interface는 findMyPost()란 추상 메소드를 가진다 2. PostCustomRepository 를 구현한 PostCustomRepositoryImpl    에 findMyPost() 메소드를 구현 한다. 3. 사용할 PostRepository Interface 에 implement를 하나 더 추가 한다. public interface PostRepository extends JpaRepository<Post, Long>, PostCustomRepository {} 4. Test source 에서 @Autowired 로 PostRepository 를 DI 하고 findMyPost() 를 호출 한다. 여기부터 질문 입니다. 제가 debug를 걸어서 postRepository (변수) 를 보니 해당 Interface는 실제 SimpleJpaRepository 객체 더군요. 그럼 postRepository 객체가 DI 되서 생기는 일을 해주는 Spring Frameowork이 기존 SimpleJpaReposity class로 객체 생성시, custom으로 추가한 findMyPost() 를 class에 추가 한후  객체 만들어서 postRepository(변수)에  attach해주는 건가요? 즉.  아래와 같은 건가요? PostRepository postRepository = new SimpleJpaRepositoy() <- findMyPost()가 추가되어 생성된 객체 

2
여섯포반장 프로필

상속 없는 Custom Repository Interface가 어떻게 동작이 가능 한 건가요?? 여섯포반장 1달 전
안녕하세요  '스프링 DATA Common2- Interface 정의' 강좌가 이해가 안됩니다 강의내용 예제 처럼 CustomRepository를 만들었고 save() 와 findAll() 메소드에는 구현체가 없는데 어떻게 data가  저장이 되고 찾아 지는건가요? 이전 강좌에서 만는 Repository interface는  JpaRepository 를 extend 받았고, 그 위로 어찌어찌 찾아가다 보니 구현 체인 SimpleJpaRepository 란 놈에서 save()가 구현 되는걸 알았습니다. 근데 아래의 제가 만든 CommentRepsoity 는 상속 받은 interface가 하나도 없는데 됩니다. Interface 위에 붙은 Annotation (@RepositoryDefinition) 때문에 알아서 내부적으로 save(), findAll() 를  구현 해주는건가요??? package com.example.SpringDataJPATest.repository;import com.example.SpringDataJPATest.domain.Comment;import org.springframework.data.repository.Repository;import org.springframework.data.repository.RepositoryDefinition;import java.io.Serializable;import java.util.List;@RepositoryDefinition(domainClass = Comment.class, idClass = Long.class)public interface CommentRepository { Comment save(Comment comment); List<Comment> findAll();}

1
여섯포반장 프로필

entityManager 객체가 null 입니다. 여섯포반장 1달 전
안녕하세요 질문이 있습니다. 선생님. "JPA 프로그래밍1 . 프로젝트 세팅을 따라 하고 있습니다." 그런데 아래 소스를 Intellij 에서 실행시 에러가 납니다. 에라가 나는 이유는 entityManager가 Null 이어서 그런데요. 왜 null 인지 모르겠습니다. 왜 entityManager가 null인지 모르겠습니다. 다 똑같이 했고, 다른점은 제가 local에 postgresql 이 있는것이 아니고,  Oracle virtual box 의 centos 안에서 docker로 postgresql을 실행 했습니다. (물론 local에서 virtualbox  안의 가상머신에 telent으로 접속도 됩니다.) package com.example.SpringDataJPATest;import org.springframework.boot.ApplicationArguments;import org.springframework.boot.ApplicationRunner;import org.springframework.stereotype.Component;import javax.persistence.EntityManager;import javax.persistence.PersistenceContext;import javax.transaction.Transactional;@Component@Transactionalpublic class JpaRunner implements ApplicationRunner { @PersistenceContext EntityManager entityManager; @Override public void run(ApplicationArguments args) throws Exception { Account account = new Account(); account.setUsername("robin"); account.setPassword("password01"); entityManager.persist(account); }}  ==application.properties 내용== spring.datasource.url=jdbc:postgresql://192.168.xx.xxx:5432/springdataspring.datasource.username=xxxspring.datasource.password=uuuuspring.jpa.hibernate.ddl-auto=createspring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=truelogging.level.org.springframework=DEBUG ==pom.xml 내용== <?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>SpringDataJPATest</artifactId> <version>0.0.1-SNAPSHOT</version> <name>SpringDataJPATest</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>javax.persistence</groupId> <artifactId>javax.persistence-api</artifactId> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> </dependency> <dependency> <groupId>jakarta.transaction</groupId> <artifactId>jakarta.transaction-api</artifactId> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-test</artifactId> <version>2.3.2.RELEASE</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>

4
홍지훈 프로필

sort 관련해서 질문이 있습니다 홍지훈 1달 전
스프링 데이터 JPA : 쿼리 메소드 Sort 강좌에서 @Query 사용시 Order by 절에서 함수를 호출하는 경우에는 Sort를 사용하지 못합니다. 그 경우에는 JpaSort.unsafe()를 사용 해야 합니다 라고 하셨으는데, 궁금한게 jpql이 아닌 repository 아래와 같은 메서드가 있을 때 sort 부분에 함수를 넣어줄 수 있나요?  List<Post> findByTitleStartsWith(String title, Sort sort);

1
안병찬 프로필

질문 있습니다. 안병찬 2달 전
1.  Runwith와 assertThat이 제대로 먹질 않습니다 ㅠㅠ assertThat같은 경우에는 해당 패키지경로를 검색해서 찾아서  import static org.assertj.core.api.Assertions.*; 이런식으로 수동 입력을 하였으나 Runwith는  https://junit.org/junit4/javadoc/latest/index.html 해당하는곳에서 레퍼런스를 찾았으나 패키지에 보이질 않네요 원래 패키지를 하나하나 찾아가며 등록해야하는건가요?? 아니면 설정이나 의존성이 잘못된 걸까요??

2
안병찬 프로필

윈도우환경일경우에는 안병찬 2달 전
postgreSQL를 그냥 단순설치하고 따라 하면 될까요? 반드시 docker의 컨테이너 생성을 해야하는지 궁금합니다..

1
하창훈 프로필

createUserId, updateUserId 와 같은 로그성 컬럼에 대한 문의를 드립니다 하창훈 2달 전
현재 JPA 도입을 검토중에 있고, 팀원들이 스터디로 JPA를 학습하고 있습니다. 지금 고민 중인 것이 있어 강사님께 질문을 드립니다. 보통 아래의 로그성 컬럼을 추가하여 해당 엔터티를 누가 생성/수정했는지 기록하고 있습니다. 엔터티 조회 (목록 조회) 시에도 최종 수정자 정보를 join을 해서 보여줘야 되고요. 예: Post table (PostEntity) 예: created_at, create_user_id, updated_at, update_user_id 질문) 이 경우, PostEntity의 create_user_id, update_user_id 컬럼에도 relation을 추가하는 것이 일반적인 관례인가요? @ManyToOne(... 생략) UserEntity createUser; @ManyToOne(...생략) UserEntity updateUser; Relation을 추가하자니, 거의 대부분의 Entity에 FK 가 생겨 뭔가 낭비같은 느낌이 들고... Relation을 추가 안하자니, 등록자, 최종사용자 정보를 Join을 할수 가 없네요. (RawQuery로 받아내야 하는..) 실무에서는 위 같은 경우 어떻게 해결하는지 문의를 드립니다. 미리 답변에 감사드립니다.

1
꽁손 프로필

이 강의 혹시 git 있나요? 꽁손 2달 전
있다면 알려주세요!

1
박원영 프로필

트랜잭션 readonly 질문 드립니다. 박원영 2달 전
기선님 안녕하세요. 강의를 보던 중 트랜잭션 readonly 속성에 대해서 궁금증이 생겨서 질문 남겨 봅니다. 조회성 메소드에 @Transaction(readonly = true) 속성을 선언하면 내부적으로 플러시가 발생하지 않게 되고, 이로인해 더티체킹을 하지 않아 성능상 이점이 있다고 설명을 해주셨는데요. 제가 이해도가 부족해서 그런지 아래와 같은 궁금증이 생겼습니다. - 단순 조회성인데 트랜잭션을 안걸면 안되나요? - 트랜잭션을 걸지 않으면 플러시도 발생하지 않아서 위의 이점을 누릴 수 있지는 않나요? - 영속 컨텍스트는 트랙잭션 별로 생성 되는 것이기 때문에 영속 컨텍스트의 이점을 누릴려면 트랜잭션을 사용 해야 되는 건가요?     - 1차 캐시 등... - 트랜잭션을 선언 하지 않으면 쿼리 조회시 영속화가 되지 않나요? - 강의과 연관된 내용은 아니지만 트랜잭션 readonly 옵션을 알아보다가 블로그 글을 보고 잘 모르는 부분이 있어서 JPA 특성인지 궁금하여 질문 남겨 봅니다. 블로그에 (https://kwonnam.pe.kr/wiki/springframework/transaction) 아래와 같은 내용이 작성되어 있는데요. 이부분이 JPA 특성인 것인지... 어떤 상황에서 아래와 같이 동작이 되는지 궁금합니다. 단, 읽기 작업만 하더라도 트랜잭션을 걸어주는 것이 좋다. 트랜잭션을 걸지 않으면 모든 SELECT 쿼리마다 commit을 하기 때문에 성능이 떨어진다. 명시적으로 트랜잭션을 걸어주면 마지막에 명시적으로 commit을 해주면 되며, commit 횟수가 줄어서 성능이 좋아진다. 이해도가 부족한 상태라 질문이 일관성이 없이 질문을 드렸네요. 항상 좋은 강의 만들어 주셔서 감사합니다.

2
꽁손 프로필

ImportBeanDefinitionRegistrar에 왜 override 안되나요? 꽁손 3달 전
따라서 해보는데 상속자체가 안되네요 ㅠㅠ 강제로 @Override해봐서 해봐도 빨간줄로  method does not override method from its superclass 라네요

3
모수혁 프로필

람다식...? 질문입니다 모수혁 3달 전
안녕하세요 선생님 다름이 아니라 post.getComments().forEach( c-> { sout (c.getComment()) 이런 부분에 대해서 공부하고 싶어서  구글에 람다식 이라고 검색 해봤으나 따로 인터페이스에서 추상메소드를 구현하는 것 만 나오고 선생님 강의에 나오는 저러한 문법은 안나오는데 검색 키워드좀 알려주실수 있나요?

1
지식공유자 되기
많은 사람들에게 배움의 기회를 주고,
경제적 보상을 받아보세요.
지식공유참여
기업 교육을 위한 인프런
“인프런 비즈니스” 를 통해 모든 팀원이 인프런의 강의들을
자유롭게 학습하는 환경을 제공하세요.
인프런 비즈니스