본문 바로가기
Blog/TIL

[240521] JdbcTemplate 파헤쳐보기

by 코젼 2024. 5. 21.
728x90
반응형

🔶Tree

🔶Annotation

🔶H2 DB

🔶JdbcTemplate

🔶DTO

🔶ORM


 

목차

       

      / 오늘의 TIL /

      db 트랜잭션 관리할 때 Jdbc -> JdbcTemplate 코드 개선을 보고 되게 신선한 충격을 받았었는데

      이번엔 h2 database와 연결해서 데이터를 접근할 때 어떻게 동작하면서 점차 개선될지 흥미진진하다!

       

      JdbcTemplate이 제공하는 주요 기능에 대해서 알아 보았다.

      • JdbcTemplate
        • 순서 기반 파라미터 바인딩 지원
      • NamedParameterJdbcTemplate
        • 이름 기반 파라미터 바인딩 지원
      • SimpleJdbcInsert
        • INSERT SQL을 편리하게 사용 가능
      • SimpleJdbcCall
        • 스토어드 프로시저를 편리하게 호출 가능

      Tree

      Node 클래스를 하나 생성해서, node값을 저장하는 value, 왼쪽 노드 left, 오른쪽노드 right를 설정한다.

      left, right는 부모 node와 연결시키기 위해 Node를 type으로 설정한다.

       

      전위, 중위, 후위 순회를 할 때, 출력문을 어느 위치에 하는지에 따라 달라진다.

      재귀함수 출력문 위치를 통해 어느 깊이까지(자식 노드 left, right) 도달하며 순회할 것인지 정한다.

      import java.io.BufferedReader;
      import java.io.InputStreamReader;
      import java.io.IOException;
      import java.util.StringTokenizer;
      
      //tree를 생성하기 위한 Node class
      class Node {
          char value;
          //재귀를 통해 Node(부모) <-> Node(자식) 간 연결을 위해 type을 Node로 설정한다.
          Node left;
          Node right;
      
          //Node 생성자
          public Node(char value) {
              this.value = value;
              this.left = null;
              this.right = null;
          }
      }
      
      public class Main {
      
          static Node[] tree;
      
          public static void main(String[] args) throws IOException {
              BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
              StringTokenizer st;
      
              int N = Integer.parseInt(br.readLine());
              tree = new Node[N+1];
      
              for (int i=0; i<N; i++) {
                  st = new StringTokenizer(br.readLine());
      
                  char parentValue = st.nextToken().charAt(0);
                  char leftValue = st.nextToken().charAt(0);
                  char rightValue = st.nextToken().charAt(0);
      
                  //부모 노드가 설정되어 있지 않은 경우
                  if (tree[parentValue - 'A'] == null) {
                      tree[parentValue - 'A'] = new Node(parentValue);
                  }
      
                  //왼쪽 노드(자식)가 있는 경우
                  if (leftValue != '.') {
                      tree[leftValue - 'A'] = new Node(leftValue);
                      //부모 노드와 연결
                      tree[parentValue - 'A'].left = tree[leftValue - 'A'];
                  }
      
                  //오른쪽 노드(자식)가 있는 경우
                  if (rightValue != '.') {
                      tree[rightValue - 'A'] = new Node(rightValue);
                      //부모 노드와 연결
                      tree[parentValue - 'A'].right = tree[rightValue - 'A'];
                  }
              }
      
              preOrder(tree[0]);
              System.out.println();
              inOrder(tree[0]);
              System.out.println();
              postOrder(tree[0]);
          }
      
          //전위순회
          private static void preOrder(Node node) {
              if (node == null) return;
      
              System.out.print(node.value);
              preOrder(node.left);
              preOrder(node.right);
          }
      
          //중위순회
          private static void inOrder(Node node) {
              if (node == null) return;
      
              inOrder(node.left);
              System.out.print(node.value);
              inOrder(node.right);
          }
      
          //후위순회
          private static void postOrder(Node node) {
              if (node == null) return;
      
              postOrder(node.left);
              postOrder(node.right);
              System.out.print(node.value);
          }
      }

       


      Annotation

      @EventListener

      ApplicationReadyEvent 클래스를 통해, 스프링 컨테이너가 완전히 초기화를 끝내고 실행 준비가 되었을 때 발생하는 이벤트이다.

      해당 어노테이션이 붙어있는 메서드를 실행한다.

       

      메모리 DB로 진행할 때, 초기 테스트 데이터를 지정할 때 사용할 수 있다.

      @SpringBootAnnotation이 있는 클래스에서 객체를 생성한 메서드에 @Bean을 지정해야 Bean으로 등록할 수 있다.

      @EventListener(ApplicationReadyEvent.class)

       

      @SpringBootApplication

      scanBasePackeages를 통해 컴포넌트 스캔을 진행할 대상을 지정할 수 있다.

      설정하지 않으면 하위 패키지 파일 모두 컴포넌트 스캔의 대상이 된다.

      @SpringBootApplication(scanBasePackages = "hello.a.b")

       

      @Profile

      프로필 설정을 통해 local 환경, 운영 환경, test 환경 등 환경에 따른 bean 등록을 구분할 수 있다.

      @Profile("local")

       

      프로필을 사용할 경우 application.properties에서 활성화 할 프로필을 따로 설정해주어야 한다.

      설정하지 않을 경우, default 값으로 프로필이 설정된다.

      spring.profiles.active=local

      H2 DB

      identity 전략

      mysql의 auto increment와 동일하다.

      generated by default as identity

      스프링 부트의 자동 리소스 등록 (bean)

      데이터베이스 접근 설정(application.properties)

       

      프로필 설정, url, username 등 데이터베이스에 접근할 수 있도록 설정을 해주면, 스프링 부트가 해당 설정을 사용해서 커넥션 풀, DataSource, 트랜잭션 매니저를 스프링 빈으로 등록해준다.


      JdbcTemplate

      JdbcTemplate 객체를 생성할 때, 'Datasource'를 parameter로 받는다.

      Identity Column 값 세팅

      insert query를 동작할 때, 자동으로 생성되는 generated by default as identity는 db에서 값을 생성한 후에 넘겨주기 때문에 애플리케이션에서는 id값을 받아서 사용해야 한다.

      따라서, 자동 증가 키 로직을 수행한 후 id를 세팅해야 한다.

      KeyHolder keyHolder = new GeneratedKeyHolder();
      
      jdbcTemplate.update(connection -> {
      	PreparedStatement ps = connection.prepareStatement(sql, new String[]{"id"}); //컬럼 값: id
          ps.set... //파라미터 세팅
          return ps;
      }, keyHolder);

       

      SimpleJdbcInsert

      executeAndReturnKey 메서드를 통해 실행 후 key를 반환해서 key(Identity Column)를 저장할 수 있다.

      스프링 빈으로 직접 등록하고 주입받아도 된다.

       

      생성자에서 table명, Identity Column명을 작성해둔다.

      this.jdbcInsert = new SimpleJdbcInsert(dataSource)
      	.withTableName("item")
          .usingGenerateKEyColumns("id");
          //.usingColumns("item_name", "price", "quantity"); //생략 가능. 생략하면 모든 컬럼 지정

      BeanPropertySqlParameterSource를 통해 parameter를 가져와서 SimpleJdbcInsert의 executeAndReturnKey 메서드에 파라미터로 넘겨서 key를 반환받는다.

      BeanPropertySqlParameterSource param = new BeanPropertySqlParameterSource(item);
      Number key = jdbcInsert.executeAndReturnKey(param);
      item.setId(key.longValue());

      NamedParameterJdbcTemplate

      동적 쿼리를 처리하기 위한 이름 지정 파라미터

      private final NamedParameterJdbcTemplate jdbcTemplate;
      
      public JdbcTemplateItemRepositoryV2(DataSource dataSource) {
          this.jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
      }

       

      종류

      1. BeanPropertySqlParameterSource
      2. MapSqlParameterSource
      3. Map

       

      파라미터 부분에 `:`로 실제 컬럼 값을 넣어서 sql문을 처리한다.

      String sql1 = "select * from item where id=?";
      String sql2 = "select * from item where id=:id"; //이름 지정 파라미터

       

      BeanPropertySqlParameterSource

      장점: connection의 prepareStatement를 통해 Identity Column과 parameter 컬럼들을 세팅해서 update를 할 필요가 없어진다.

       

      파라미터 내에 있는 값들의 getter, setter를 가져와서 parameter에 넣는다.

      SqlParameterSource param = new BeanPropertySqlParameterSource(item); //객체를 파라미터로 받는다.

       

      MapSqlParameterSource

      parameter에 id처럼 Identity Column이 존재해서 BeanPropertySqlParameterSource로 처리할 수 없는 경우 사용한다.

      메서드의 파라미터로 전달받은 id로 update한다.

      SqlParameterSource param = new MapSqlParameterSource()
      	.addValue("paramName", getter());

       

      Map

      map의 key, value를 통해 parameter를 세팅할 수 있다.

      Map<String, Object> param = Map.of("id", id);

       


      BeanPropertyRowMapper

      JdbcTemplate에서 id를 통해 데이터를 검색할 때(ex. findById), queryForObject 메서드를 사용하는데, 이 때 파라미터로 들어오는 RowMapper는 BeanPropertyRowMapper로 쉽게 처리할 수 있다.

      private RowMapper<Item> itemRowMapper() {
      	return BeanPropertyRowMApper.newInstance(Item.class);
      }

       


      기타

      DTO

      Data Transfer Object, 데이터 전송 객체

      객체의 주 목적이 데이터를 전송하는 것이라면 DTO라고 할 수 있다.


      ORM

      Object Relational Mapping, 객체 관계 매핑

      SQL query를 직접 작성하는 것이 아닌 객체를 통해 DB 테이블을 매핑 시켜준다.

      JPA interface를 주로 뜻한다. JPA의 주요 구현체로는 Hibernate가 있다.

      728x90
      반응형

      'Blog > TIL' 카테고리의 다른 글

      [240526] API 개발하기  (0) 2024.05.26
      [240524] 수학 지식을 넓히자  (0) 2024.05.24
      [240523] 배워도 배워도 끝이 없네  (0) 2024.05.23
      [240522] 드디어 JPA를 접하다  (0) 2024.05.22
      [240520] 암기하지말고 이해하기  (0) 2024.05.20

      댓글