Spring Boot 3 & Spring Framework 6 - Section 10 :

이정수·2024년 8월 12일
0

Udemy학습-Spring & React

목록 보기
13/21
post-thumbnail

Spring JPA를 활용하여 H2 In-Memory DB 사용하기.

JPA 또는 Spring Data JPA를 활용 시 DB에 Mapping하여 연결 및 쉽게 상호작용할 수 있다.

  • 필요한 Framework 사전 준비
    spring-boot-starter-data-jpa , h2
    • dependency 정의
      pom.xml에 다음 구문을 추가 후 Maven을 재실행.
    <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>   
    <dependency>
                <groupId>com.h2database</groupId>
                <artifactId>h2</artifactId>
                <!--jar파일의 일부에 h2 db가 포함되지 않도록 scope를 설정.-->
                <scope>runtime</scope> 
    </dependency>


  • h2-DB 관련 Spring Security 추가 설정 Spring Security
    localhost:8080/h2-console로 진입시, 다음 오류가 발생하면서 Application에서 연결을 거부.

    403 Forbidden : Client가 요청한 Resource에 대해 접근 권한이 없음을 지시
    h2-console url 접속 시 Spring SecurityCSRF Protection에 의해 접근금지.

    CSRF protection 비활성화, h2-console Frame 활성화 설정
    Spring Security에서는 default로 CSRF protection 활성화, Frame 비활성화로 설정되어있음.

    Spring SecurityFilterChain 설정
    SecurityFilterChain에 대한 전반적인 설정을 구현
    기본기능( Default )과 추가기능( Additional )을 모두 구현해야한다.

    @Configuration이 선언된 WebSecurityConfiguration을 수행하는 Class에 다음 SecurityFilterChain를 반환하는 FilterChain @Bean Method를 선언.

    @Bean
        public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
            // 인증된 Http Request에 대해 승인처리 설정.
            http.authorizeHttpRequests(
                    auth->auth.anyRequest().authenticated()
            );
            // 인증되지않은 Http Request에 대해 로그인 양식 도출.
            http.formLogin(Customizer.withDefaults());
            // CSRF 비활성화
            http.csrf(csrf->csrf.disable());
            // FrameOption 비활성화
            http.headers(header->header.frameOptions(frameOption->frameOption.disable()));
            // SecurityFilterChain instance를 Spring bean으로 반환
            return http.build();
        }

    HttpSecurity instance를 매개변수로하여 SecurityFilterChain type의 Spring Bean instance를 생성 및 return하는 @Bean method를 구현.
    @Bean method에서는 HttpSecurity instance를 이용하여 SecurityFilterChain의 기본기능( Default )과 추가기능( Additional )을 모두 구현 후 HttpSecurity instance를 반환.

    Filter Chain @Bean methodthrows Exception이 구현된 이유?
    return되는 http.build()에서 Exception이 발생하므로.

    。다음 구문을 Spring Security 설정에 관여하는 Class( SpringSecurityConfig.java )에 추가 할 경우, h2-console에 진입이 가능해짐!

    @Bean
        public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
            return http.authorizeHttpRequests(
                    auth->auth.anyRequest().authenticated()
            )
         	.formLogin(Customizer.withDefaults())
         	.csrf(csrf->csrf.disable())
            .headers(header->header.frameOptions(frameOption->frameOption.disable()))
            .build();
        }

    ▶ 다음처럼 HttpSecurity instance의 Configuration 연쇄적으로 연결하여 SecurityFilterChain 구현이 가능하다.

    • 기본기능 : 인증이 된 모든 Http Request에 대해 승인
      Spring Application에 전달되는 모든 HTTP Request에 대해서 인증된 HTTP Request에 대해서만 승인.
    http.authorizeHttpRequests(
                    auth->auth.anyRequest().authenticated()
            );

    。특정 HttpSecurity객체에 대하여 input된 인증이 된 모든 HttpRequest에 대하여 승인처리 설정.
    구현하지 않는 경우, 모든 HTTP Request에 대해서 거절하면서 Authentication을 비활성화

    • 기본기능 : 인증되지 않은 http요청에 대해 로그인 양식 표현
      http.formLogin(Customizer.withDefaults());
      formLogin()에 관련된 모든 기본값인 withDefaults()를 설정.
      withDefaults()는 Customizer class의 static method로서 정의됨.

    • 추가기능 : CSRF 비활성화
      http.csrf().disable();

    • 추가기능 : h2-console frame 옵션 활성화
      http.headers().frameOptions().disable();
      headerFrameOption을 Disable하면 h2-console frame을 사용 가능.

    • Spring Security에 설정될 SecurityFilterChain instance 생성 및 Spring Bean instance으로 return
      HttpSecurity객체.build() :
      。설정된 HttpSecurity instance로 SecurityFilterChain instance를 생성하여 반환.
      @Bean에 의해 Spring Bean instance으로 반환.

      。이후 localhost:8080/h2-console 접속 시 Spring의 로그인 양식이 도출.

      localhost:8080/login : Spring 로그인 Page 도출
      localhost:8080/logout : 기존 로그인된 자격증명을 로그아웃.
      ▶ HTML의 <a class="nav-link" href="/logout">으로 간단하게 로그아웃 버튼을 생성할 수 있다.

      WebSecurityConfiguration :
      Spring Security의 웹보안 Configuration을 담당하는 @Configuration Class.
      @Bean Method를 생성 후 SecurityFilterChain instance를 활용하여 Authentication , Authorization , CSRF Protection 등의 보안정책을 해당 Configuration Class에서 설정이 가능.

      SpringBootWebSecurityConfiguration
      Servlet Application을 보호하는 역할의 웹보안 Configuration Class.
      ▶ 웹보안을 위한 Default로 설정된 Configuration Class.

      Spring은 기본적으로 명시적으로 인증된 HTTP Request에 대해서만 허용 및 formLogin()httpBasic()이 기본적으로 활성화 설정되도록 설정됨.
      CSRF Protection은 비명시적으로 활성화 설정.

  • Spring JPA를 활용해 Spring Bean을 DB Table에 Mapping하기 JPA 관련 학습 내용
    @EntityJpaRepository<DBEntity class, id data Type> 활용.

    Spring JPA :
    SQL , EntityManager을 사용하지 않는다.
    EntityManager 대신 JpaRepository<Entity class, ID> Interface를 상속하여 활용.
    • Todo Class를 Spring Bean으로서 DB Table과 Mapping하기
      @GeneratedValue : Primary Key를 자동할당.
      Spring Boot Auto Configuration에 의해 @Entity가 식별 될 경우, 자동으로 H2-DBDB Table을 생성!
    @Entity(name = "TodoABC") // TodoABC 이름의 Table 생성.
    public class Todo {
        public Todo(){};
        public Todo(int id, String username, String description, LocalDate targetDate, boolean completed) {
            super();
            this.id = id;
            this.username = username;
            this.description = description;
            this.targetDate = targetDate;
            this.completed = completed;
        }
        @Id
        @GeneratedValue // Pk값을 자동 할당.
        private int id;
        @Column(name="userID") // 생성될 DB Table의 column명 변경.
        private String username;
        @Size(min = 10, message="Enter at least 10 characters")
        private String description;
        private LocalDate targetDate;
        private boolean completed;


    。Application 구동 시 초기 DB Table을 정의하는 schema.sql을 작성하지 않아도 Spring Auto Configuration에 의해 h2-DBDB Table이 자동생성.
    。생성될 Table의 이름과 Column의 이름을 임의 변경 가능!

    • Spring Bean의 변수명에 대문자가 존재하는 경우 앞에 _로 지시.
      ex) targetDate => TARGET_DATE


  • DB Table에 삽입할 초기 데이터를 정의하기
    schema.sql :
    Application 초기화 시 초기 정의될 DB Schema를 정의하는 파일.
    Schema : DB 구조로서 Table, View, Index등의 객체를 정의.

    data.sql :
    Application 초기화 시 정의된 DB Table에 삽입할 초기 데이터를 정의하는 파일

    。실행 순서 : schema.sql -> data.sql
    • src/main/resources에 초기화 데이터가 작성된 data.sql을 작성
    insert into todoabc(id,userid,description,target_date,completed)
    values(10001,'wjdtn747','Get AWS Certified',CURRENT_DATE(),false),
          (10002,'wjdtn2','Get Azure Certified',CURRENT_DATE(),false),
          (10003,'wjdtn3','Get GCP Certified',CURRENT_DATE(),false),
          (10004,'wjdtn4','Get DevOps Certified',CURRENT_DATE(),false);
    • application.properties에 다음 구문을 추가하기
      spring.jpa.defer-datasource-initialization=true
      。기본적으로 Spring에서는 @Entity가 선언된 Class를 처리되기 이전(or hibernate 초기화 이전)에 DataSource( sql등 )를 우선 실행하며, 이는 Spring Auto Configuration에 의해 DB Table이 생성되기 이전 data.sql이 먼저 실행하게되어 오류가 발생하게 된다.
      ▶ 해당 구문을 선언할 경우, DataSource의 초기화를 지연하면서 DB table이 생성된 이후( hibernate 초기화 이후 )에 data.sql이 실행되도록 변경함.

      ▶ 다음처럼 data.sql에 의해 초기 데이터가 설정되게된다.
      H2 DBIn-Memory DB 이므로, 서버 재실행 시 초기 데이터로 초기화.


  • Spring JPAJpaRepository 기능을 활용하여 Todo instance를 추가, 삭제, 검색 등의 작업 구현하기.
    。기존 listTodos.jspTodoService.javaStatic List와 상호작용.
    ▶ 추가적으로 H2 DB와 상호작용하는 기능 구현하기.
    Static List를 활용한 Spring Data JPA 참고하기
    • JpaRepository<DBEntity class, id data Type>를 상속하는 Interface 생성.
      。Field명으로 검색하는 Custom Method 구현하기
        // TodoJpaRepository.interface
    import org.springframework.data.jpa.repository.JpaRepository;
    public interface TodoJpaRepository extends JpaRepository<Todo,Long> { }

    JpaRepository는 DB의 Id로 검색하는 findById()는 기본적으로 제공하지만, Field명으로 검색하는 기능은 구현이 되지 않았으므로, Custom Method를 구현.

    import org.springframework.data.jpa.repository.JpaRepository;
    import java.util.List;
    public interface TodoJpaRepository extends JpaRepository<Todo,Long> {
        // Todo Class의 field명으로 DB Table의 Data를 조회하는 Custom Method
        List<Todo> findByusername(String username);
    }

    JpaRepository를 상속한 Interface에 생성할 Custom Method를 서식.
    Custom Method 작성 시 SpringDataJpa Interface 내에 명명 규칙을 지켜서 작성.
    ▶ 명명규칙 : findByName1()의 매개변수의 이름은 반드시 DB Entity Class의 Field명(name1)과 동일.
    Custom Method의 매개변수를 Spring Bean의 Field명과 동일하게 설정 시 Spring Data JPA가 자동으로 검색

    Custom method 작성 시 SpringDataJpa Interface 내에서 명명 규칙을 지켜서 작성.

    • 기존의 Static List가 아닌 DB Table과 상호작용하는 Controller class 구축하기.
      。기존의 TodoController.java를 재활용.
    import jakarta.validation.Valid;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.ModelMap;
    import org.springframework.validation.BindingResult;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.SessionAttributes;
    import java.time.LocalDate;
    import java.util.List;
    @Controller
    @SessionAttributes("name")
    public class TodoControllerJpa {
        // JpaRepository를 상속받은 SpringDataJpa interface의 객체 생성
        // @Autowired는 생성자의 인수를 통해 설정됨.
        private TodoRepository todoRepository;
        @Autowired
        public TodoControllerJpa(TodoRepository todoRepository){
            this.todoRepository = todoRepository;
        }
        @RequestMapping("list-todo")
        public String ListAllTodos(ModelMap map){
            String userName = getLoggedInUserName(map);
            // DB Table에서 data를 Todo(= Bean )의 username 필드의 이름으로 검색하여 가져옴.
            List<Todo> todos = todoRepository.findByUsername(userName);
            map.addAttribute("todos",todos);
            return "listTodos";
        }
        private static String getLoggedInUserName(ModelMap map) {
            Authentication authentication =
                    SecurityContextHolder.getContext().getAuthentication();
            return authentication.getName();
        }
        @RequestMapping(value = "add-todo", method= RequestMethod.GET)
        public String ShowNewTodoPage(ModelMap model){
            String userName = getLoggedInUserName(model);
            Todo todo = new Todo(0,userName,"",LocalDate.now().plusYears(1),false);
            model.put("todo",todo);
            return "Todo";
        }
        @RequestMapping(value = "add-todo", method= RequestMethod.POST)
        public String addTodoPage(ModelMap model ,@Valid Todo todo, BindingResult result){
            if(result.hasErrors()){
                return "Todo";
            }
            String username = getLoggedInUserName(model);
            todo.setUsername(username);
            todoRepository.save(todo);
            return "redirect:list-todo";
        }
        @RequestMapping("delete-todo")
        public String DeleteTodo(@RequestParam int id){
            todoRepository.deleteById(id);
            return "redirect:list-todo";
        }
        @RequestMapping(value = "update-todo", method=RequestMethod.GET)
        public String showUpdateTodoPage(@RequestParam int id, ModelMap model){
            Todo todo = todoRepository.findById(id).get();
            model.put("todo",todo);
            return "Todo";
        }
        @RequestMapping(value = "update-todo", method=RequestMethod.POST)
        public String UpdateTodo(@RequestParam int id, ModelMap model , @Valid Todo todo, BindingResult result){
            todoRepository.deleteById(id);
            if(result.hasErrors()){
                return "Todo";
            }
            String username = getLoggedInUserName(model);
            todo.setUsername(username);
            todoRepository.save(todo);
            return "redirect:list-todo";
        }
    }
    • JpaRepository를 상속한 Interface의 instance를 생성 후 생성자 Dependency-Injection를 통해 @Autowired하여 의존성을 주입
    // JpaRepository를 통한 DB Table과 상호작용
        private TodoJpaRepository todoJpaRepository;
        // Static List와 상호작용
        private TodoService todoService;
        // 생성자기반 Dependency Injection.
        // @Autowired
        public TodoController(TodoService todoService, TodoJpaRepository todoJpaRepository) {
            this.todoService = todoService;
            this.todoJpaRepository = todoJpaRepository;
        }
    • 기존 Controller Method에 TodoJpaRepositoy interface에서 정의한 Custom method 활용하기.
    @RequestMapping("list-todo")
        public String ListAllTodos(ModelMap model){
            String username = getLoggedinUsername(model);
            List<Todo> todos = todoJpaRepository.findByusername(username);
            model.put("todos",todos);
            return "listTodos";
        }
        private String getLoggedinUsername(ModelMap model){
            Authentication auth = SecurityContextHolder.getContext().getAuthentication();
            return auth.getName();
        }

    。해당 Custom Method( todoRepository.findByUsername(userName) )는 DBTable에서 Data를 Spring Bean ( Todo ) instance의 Field명(username)으로 Entity를 검색하여 Todo instance로 가져온다.

    getLoggedinUsername() : 실행중인 threadSecurityContextAuthentication instance에서 username를 가져오는 Method 생성. Authention

    。Custom Method를 통해 DB Table에서 "wjdtn747"username으로 data를 검색하여 가져온 Spring Bean( = Todo ) instance를 통해 Data가 도출.

    • DB Table에 Spring Bean instance를 추가하는 Method 구현하기.
      。기존 Static ListSpring Bean을 추가할 때, 모든 field를 각각 인수로 받아 생성하여 추가.
      JpaRepositorySpring Bean Class의 Field를 받는 method가 존재하지 않으므로, Spring Bean의 모든 Field의 값을 사전에 설정한 후 save()를 통해 DB Table에 추가.
    @RequestMapping(value = "add-todo", method = RequestMethod.POST)
        public String addTodo(ModelMap model, @Valid Todo todo, BindingResult result){
            if (result.hasErrors()) {
                System.out.println(todo.getId());
                return "addTodo";
            }else {
                String username = getLoggedinUsername(model);
                todo.setUsername(username);
                todoJpaRepository.save(todo);
                return "redirect:list-todo";
            }
        }

    addTodo.jsp에서 POST<form> Data 전송 시 <form:form method="post" modelAttribute="todo">를 통해 Controller Method addTodo()의 매개변수 Todo todoData Binding되어 Model 객체로서 선언 후 username를 지정하여 H2-DBtodoabc DB에 추가.
    Spring MVC에 의해 <form:form>Controller Method의 매개변수 todo Spring Bean instance를 Model 객체로서 Data Binding 되었으므로, addTodo.jsp에서 작성한 <form:input type="text" path="description" required="required"/>의 내용이 tododescription field에 그대로 저장되어있음.

    addTodo.jsp에서 <form:form>에서 입력된 값이 그대로 Spring Bean으로 Binding된 후 save()를 통해 Todo Class와 @Entity로 Binding된 DB의 todoabc Table로 추가됨.


    • DB Table의 Todo instance를 삭제하는 Method 구현
      JpaRepository객체.deleteById(id) method 활용.
    @RequestMapping("delete-todo")
        public String deleteTodo(@RequestParam int id){
            todoJpaRepository.deleteById(id);
            return "redirect:list-todo";
        }
    • DB Table의 Todo Instance를 Update하는 Method 구현
      JpaRepository객체.save(DBEntity)INSERTUPDATE를 수행.
      기존 DB EntityUPDATE , 새로운 DB EntityINSERT
      DELETEINSERT를 수행하는 경우 동시성 문제가 발생하므로 주의.
       @RequestMapping(value="update-todo",method=RequestMethod.GET)
        public String UpdateTodo(@RequestParam int id, ModelMap model){
            Todo todo = todoJpaRepository.findById(id).get();
            model.put("todo",todo);
            return "addTodo";
        }
        @RequestMapping(value="update-todo",method=RequestMethod.POST)
        public String UpdateTodo(@RequestParam int id,ModelMap model, @Valid Todo todo, BindingResult result){
            todoJpaRepository.save(todo);
            if (result.hasErrors()) {
                return "addTodo";
            }
            String username = getLoggedinUsername(model);
            todo.setUsername(username);
            return "redirect:list-todo";
        }

    GET : addTodo.jsp<form:form method="post" modelAttribute="todo">로 인한 Data Binding 될 Model 객체로서의 Spring Bean을 요구하므로, JpaRepository객체.findById(id).get()으로 DBTable에서 Update할 Spring Bean을 가져와서 Model 객체로 적용.

    POST :
    todoJpaRepository.deleteById(id); : DB Table의 수정할 기존에 존재하는 Entity를 삭제
    ▶ 이후 Controller method addTodo()와 동일한 방식으로 Todo instance를 todoJpaRepository.save(todo)를 통해 추가.

    • H2 DB와 Todo List가 잘 연동되는지 확인.

  • JPA 사용 시, Background에서 어떤 SQL query가 생성되는지 확인하는 방법
    JpaRepository<>를 활용한 Spring JPA의 method(save(), findById() )의 Query 확인용도로도 사용됨.
    。다음 구문을 application.properties로 추가
    spring.jpa.show-sql=true

    。웹페이지 상에서 DB와 관련된 작업을 수행하면 콘솔창에 해당 작업의 query문이 표시됨.
    ▶ Spring Data JPA 활용 시 사용자가 SQL을 사용하진 않지만, 백그라운드상에서는 SQL이 활용됨.

MySQL을 Docker Container로서 실행한 후 Application에 MySQL DB를 연결하기.

  • Docker :
    Container를 사용해서 Application을 신속하게 구축, 테스트 및 배포할 수 있는 오픈소스 SW 플랫폼.
    。동일한 Docker Container일 경우 다른 Linux에서도 동일한 실행 환경을 제공하는 Tool. => 가상머신과 유사

    Container :
    。개발자가 Library, 종속성 등 필요한 모든 것을 이용하여 Application을 Packaging하여 하나의 Package로 배포할 수 있게하는 역할을 수행.
    ▶ OS 없이, Host의 Resource를 그대로 사용하는 Application

    。서버 운영을 위한 Library만 Image에 포함하여 설치하므로, 경량화됨.
    ▶ Image : Object , Container : Instance

  • Docker를 이용해서 MySQL 실행
    • 다음 구문을 Powershell에 입력 후 실행하기.
      。MySQL에 속한 Container를 생성하는 구문
      env로 수많은 환경변수가 설정되어있음.
      docker run --detach --env MYSQL_ROOT_PASSWORD=dummypassword --env MYSQL_USER=todos-user --env MYSQL_PASSWORD=dummytodos --env MYSQL_DATABASE=todos --name mysql --publish 3306:3306 mysql:8-oracle

    • docker container ls :
      모든 Docker Container를 표시.
      • 포트 3306 관련 오류 발생시 입력.
        netstat -ano | findstr 3306
        PID 번호 조회 후 입력
        taskkill /pid PID번호 /f
        ex) PID번호 : 6864 일 경우
        taskkill /pid 6864 /f
      • Docker 코드 설명
        docker run --detach :
        --env MYSQL_ROOT_PASSWORD=dummypassword 
        --env MYSQL_USER=todos-user 
        --env MYSQL_PASSWORD=dummytodos 
        --env MYSQL_DATABASE=todos 
        --name mysql 
        --publish 3306:3306 
        mysql:8-oracle

      docker run : 해당 명령어로 mysql 실행
      MYSQL_ROOT_PASSWORD : DB의 ROOT PW 설정
      MYSQL_USER : 사용자 계정 ID
      MYSQL_PASSWORD : 사용자 계정 PW
      MYSQL_DATABASE : 설정된 이름의 DB Schema를 생성
      name : Docker Container 이름 설정
      publish 3306:3306 : Container를 3306 포트로 실행.
      => 포트를 할당하는 이유 ? :
      OS에서 뭔가를 실행할 경우 포트를 할당해야하므로.
      mysql:8-oracle : MySQL Image의 이름과 버전을 지시하며 해당 8-oracle 태그는 아무 OS(Linux, Mac, Windows)에 관계없이 실행가능.

    • application.properties에 다음을 입력
      • h2 DB 관련 설정은 모두 비활성화.
      spring.jpa.hibernate.ddl-auto=update
      spring.datasource.url=jdbc:mysql://localhost:3306/todos
      spring.datasource.username=todos-user
      spring.datasource.password=dummytodos
      spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
      • spring.jpa.hibernate.ddl-auto :
        。h2가 아닌 다른 DB에서 Bean에 대응하는 Table을 자동으로 생성할 수 있게 설정.
        => Spring Boot는 h2 DB에 대해서만 자동으로 Table을 생성하므로 따로 설정해야함.
        => 해당 구문 선언 시 Application을 실행할 때 현재 @Entity가 선언된 Bean(= Entity) 기반으로 DB Schema가 구축됨.
      • spring.datasource.url : MySQL DB가 실행되는 URL을 정의
        。URL 정의시 jdbc로 연결하므로 http를 작성하지 않고, Docker Container에서 정의한 포트번호, DB이름을 입력해야함.
        ex ) jdbc:mysql://localhost:포트번호/DB이름
      • spring.datasource.username :
        Docker Container에서 정의한 사용자 계정 ID 입력
      • spring.datasource.password :
        Docker Container에서 정의한 사용자 계정 PW 입력
      • spring.jpa.properties.hibernate.dialect : dialect(방언) 설정.
        。ORM은 객체 Mapping으로 자동으로 query를 작성하는데, 수 많은 DBMS 종류마다 Query문이 각개 다르므로, 이를 지시하도록 DB 유형을 지정.
    • pom.xml에 MySQL dependency를 추가.(Spring Boot 3.1 이상 사용시)
      。기존 h2 database의 dependency는 삭제한다.
     <dependency>
                <groupId>com.mysql</groupId>
                <artifactId>mysql-connector-j</artifactId>
     </dependency>
  • Application과 MySQL이 연동되었는지 확인하기
    。localhost:8080/ 으로 진입 후 list-todo에서 todo를 생성하고 MySQL에서 생성되었는지 확인.
    • 관리자권한으로 Powershell을 실행한 후 mysqlsh 입력.
    • MySQLShell에서 \connect todos-user@localhost:3306 입력한 후 PW를 입력하기.
      。DB사용자 이름을 통해 3306 포트로 실행되는 DB로 연결.
    • \use todos를 입력한 후 \sql을 입력하여 sql 구문을 통해 입력된 데이터를 조회 가능.
      \use todos : 해당 DB schema 사용 선언.

      。다음처럼 Add Todo를 통해 업로드된 데이터를 Mysql DB에서 조회가 가능하다!
  • DB에 생성된 데이터는 영속성이므로, Application을 재실행해도 임의로 추가한 Todo가 다시 나타난다.
profile
공부기록 블로그

0개의 댓글