ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Back End] Spring JDBC
    Web Development/부스트코스 - Back-End(Java) 2020. 3. 30. 22:05

    ✔️ Spring JDBC

    ◾ JDBC를 이용해서 프로그래밍을 하게 되면 반복적인 코드가 많이 발생한다.

    ◾ 반복적인 코드는 개발자의 생산성을 떨어뜨리는 주된 원인이다.

    반복적인 JDBC의 모든 저수준 세부사항을 Spring JDBC가 처리해준다.

    Spring JDBC를 사용하여 개발자는 필요한 부분만 개발하면 된다.

    ◾ Spring JDBC 외에 JPA, MyBatis 등의 기술들이 존재한다.

     

    Spirng JDBC와 개발자가 해야 할 일

     

    1️⃣ Spring JDBC 패키지

     org.springframework.jdbc.core

    - JdbcTemplate 및 관련 Helper 객체 제공

     org.springframework.jdbc.datasource

    - DataSource를 쉽게 접근하기 위한 유틸 클래스, 트랜젝션매니져 및 다양한 DataSource 구현을 제공

     org.springframework.jdbc.object

    - RDBMS 조회, 갱신, 저장등을 안전하고 재사용 가능한 객제 제공

     org.springframework.jdbc.support

    - jdbc.core 및 jdbc.object를 사용하는 JDBC 프레임워크를 지원

     

    2️⃣ JDBC Template

    org.springframework.jdbc.core에서 가장 중요한 클래스입니다.

     리소스 생성, 해지를 처리해서 연결을 닫는 것을 잊어 발생하는 문제 등을 피할 수 있도록 합니다.

     스테이먼트(Statement)의 생성과 실행을 처리합니다.

     SQL 조회, 업데이트, 저장 프로시저 호출, ResultSet 반복호출 등을 실행합니다.

     JDBC 예외가 발생할 경우 org.springframework.dao패키지에 정의되어 있는 일반적인 예외로 변환시킵니다.

     


    ✔️ DTO ( Data Transfer Object )

    DTO란 Data Transfer Object의 약자입니다.

     계층간 데이터 교환을 위한 자바빈즈입니다.

     여기서의 계층이란 컨트롤러 뷰, 비지니스 계층, 퍼시스턴스 계층을 의미합니다.

     일반적으로 DTO는 로직을 가지고 있지 않고, 순수한 데이터 객체입니다.

     필드와 getter, setter를 가진다. 추가적으로 toString(), equals(), hashCode()등의 Object 메소드를 오버라이딩 할 수 있습니다.

     

    💾 DTO의 예

    public class ActorDTO {
    
        private Long id;
        private String firstName;
        private String lastName;
        
        public String getFirstName() {
            return this.firstName;
        }
        
        public String getLastName() {
            return this.lastName;
        }
        
        public Long getId() {
            return this.id;
        }
        // ......
    }

     


    ✔️ DAO ( Data Access Object )

    데이터를 조회하거나 조작하는 기능을 전담하도록 만든 객체

    보통 데이터베이스를 조작하는 기능을 전담하는 목적으로 만들어진다. 

     


    ✔️ Connection Pool

    ◾ DB 연결은 비용이 많이 든다.

    ◾ 커넥션 풀은 미리 커넥션을 여러개 맺어 둔다.

    ◾ 커넥션이 필요하면 커넥션 풀에게 커넥션을 빌리서 사용한 후 반납한다.

     

    Connection Pool


    ✔️ Data Source

    DataSource는 커넥션 풀을 관리하는 목적으로 사용되는 객체입니다.

    DataSource를 이용해 커넥션을 얻어오고 반납하는 등의 작업을 수행합니다.

     


    ✔️ Spring JDBC 실습

     

    ◾ ApplicationContext : 스프링이 제공하는 IoC / DI 컨테이너

    ApplicationConfig 클래스를 통해 ApplicationContext가 설정된다. 

    DataSource 객체를 통해 DB 커넥션을 수행한다. 

    ◾ DTO, DAO 

    ◾ RoleDaoSqls : Dao에서 사용할 SQL 보관 

    ◾ NamedParameterJdbcTemplate, SimpleJdbcInsert는 Spring JDBC가 제공해 주는 것들이다. 

     

    💾 pom.xml : Spring JDBC 사용을 위한 설정(의존성 추가 등)

    더보기
    <?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>kr.or.connect</groupId>
      <artifactId>daoexam</artifactId>
      <version>0.0.1-SNAPSHOT</version>
    
      <name>daoexam</name>
      <!-- FIXME change it to the project's website -->
      <url>http://www.example.com</url>
    
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
        <spring.version> 5.2.5.RELEASE</spring.version>
      </properties>
    
       <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.11</version>
          <scope>test</scope>
        </dependency>
        
        <!-- Spring -->
    	<dependency>
    		<groupId>org.springframework</groupId>
    		<artifactId>spring-context</artifactId>
    		<version>${spring.version}</version>
    	</dependency>
    		
    	<!-- Spring JDBC-->	
    	<dependency>
    		<groupId>org.springframework</groupId>
    		<artifactId>spring-jdbc</artifactId>
    		<version>${spring.version}</version>
    	</dependency>  
    		 
        <!-- Spring tx -->		 
    	<dependency>
    		<groupId>org.springframework</groupId>
    		<artifactId>spring-tx</artifactId>
    		<version>${spring.version}</version>
    	</dependency>
    	
    	<!-- MySQL -->	
    	<dependency>
    		<groupId>mysql</groupId>
    		<artifactId>mysql-connector-java</artifactId>
    		<version>5.1.21</version>
    	</dependency>
    	
    	<!-- data source -->
    	<dependency>
    		<groupId>org.apache.commons</groupId>
    		<artifactId>commons-dbcp2</artifactId>
    		<version>2.1.1</version>
    	</dependency>
      </dependencies>
    
      <build>
        <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
          <plugins>
            <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
            <plugin>
              <artifactId>maven-clean-plugin</artifactId>
              <version>3.1.0</version>
            </plugin>
            <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
            <plugin>
              <artifactId>maven-resources-plugin</artifactId>
              <version>3.0.2</version>
            </plugin>
            <plugin>
              <artifactId>maven-compiler-plugin</artifactId>
              <version>3.8.0</version>
            </plugin>
            <plugin>
              <artifactId>maven-surefire-plugin</artifactId>
              <version>2.22.1</version>
            </plugin>
            <plugin>
              <artifactId>maven-jar-plugin</artifactId>
              <version>3.0.2</version>
            </plugin>
            <plugin>
              <artifactId>maven-install-plugin</artifactId>
              <version>2.5.2</version>
            </plugin>
            <plugin>
              <artifactId>maven-deploy-plugin</artifactId>
              <version>2.8.2</version>
            </plugin>
            <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
            <plugin>
              <artifactId>maven-site-plugin</artifactId>
              <version>3.7.1</version>
            </plugin>
            <plugin>
              <artifactId>maven-project-info-reports-plugin</artifactId>
              <version>3.0.0</version>
            </plugin>
            <!-- Java 1.8 -->
            <plugin>
    		  <groupId>org.apache.maven.plugins</groupId>
    		  <artifactId>maven-compiler-plugin</artifactId>
    		  <version>3.6.1</version>
    		  <configuration>
    		  <source>1.8</source>
    		  <target>1.8</target>
    		  </configuration>
    		</plugin>
          </plugins>
        </pluginManagement>
      </build>
    </project>
    

     

    💾 ApplicationContfig.java : 스프링 IoC/DI 컨네이너 설정을 위한 클래스

    더보기
    package kr.or.connect.daoexam.config;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;
    
    @Configuration //Configuration 클래스 
    @ComponentScan(basePackages = { "kr.or.connect.daoexam.dao" }) // 이렇게 패키지를 추가할 수 있다. 패키지 여러개 추가도 가능.
    @Import({DBConfig.class}) // IoC / DI 컨테이너 설정을 여러 클래스로 나눠서 할 수 있음. DB관련설정은 DBConfig 클래스에서 할것임.
    public class ApplicationConfig {
    
    }

    💾 DBConfig.java : 스프링 IoC/DI 컨네이너 설정을 위한 클래스 ( DB 관련 )

    더보기
    package kr.or.connect.daoexam.config;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;
    
    @Configuration //Configuration 클래스 
    @ComponentScan(basePackages = { "kr.or.connect.daoexam.dao" })
    @Import({DBConfig.class}) // IoC, DI 컨테이너 설정을 여러 클래스로 나눠서 할 수 있음. DB관련설정은 DBConfig 클래스에서 할것임.
    public class ApplicationConfig {
    
    }

     

    💾 Role.java : DTO

    더보기
    public class Role {
    
    	private int roleId;
    	private String description;
    	
    	public int getRoleId() {
    		return roleId;
    	}
        
    	public void setRoleId(int roleId) {
    		this.roleId = roleId;
    	}
        
    	public String getDescription() {
    		return description;
    	}
        
    	public void setDescription(String description) {
    		this.description = description;
    	}
        
    	@Override
    	public String toString() {
    		return "Role [roleId=" + roleId + ", description=" + description + "]";
    	}
    	
    }

    💾 RoleDaoSqls.java : SQL문을 가지고 있는 객체

    더보기
    package kr.or.connect.daoexam.dao;
    
    public class RoleDaoSqls {  
       //상수는 대문자로 쓰는 것이 관례
        public static final String SELECT_ALL = "SELECT role_id, description FROM role order by role_id";
        public static final String UPDATE = "UPDATE role SET description = :description WHERE ROLE_ID = :roleId";
        public static final String SELECT_BY_ROLE_ID = "SELECT role_id, description FROM role where role_id = :roleId";
        public static final String DELETE_BY_ROLE_ID = "DELETE FROM role WHERE role_id = :roleId";  
    }
    

     

    💾 RoleDao.java : DAO

    더보기
    package kr.or.connect.daoexam.dao;
    
    import static kr.or.connect.daoexam.dao.RoleDaoSqls.*;
    
    import java.util.Collections;
    import java.util.List;
    import java.util.Map;
    
    import javax.sql.DataSource;
    
    import org.springframework.dao.EmptyResultDataAccessException;
    import org.springframework.jdbc.core.BeanPropertyRowMapper;
    import org.springframework.jdbc.core.RowMapper;
    import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
    import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
    import org.springframework.jdbc.core.namedparam.SqlParameterSource;
    import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
    import org.springframework.stereotype.Repository;
    
    import kr.or.connect.daoexam.dto.Role;
    import static kr.or.connect.daoexam.dao.RoleDaoSqls.*;
    
    // 나중에 @autoWierd 어노테이션을 사용해 DI를 하기위해 @Repository를 붙여준다. DAO에는 @Repository를 붙여야한다.
    @Repository
    public class RoleDao {
      private NamedParameterJdbcTemplate jdbc; // 이름을 이용해서 바인딩을하거나 결과값을 가져올떄 사용
      private SimpleJdbcInsert insertAction;
      private RowMapper<Role> rowMapper = BeanPropertyRowMapper.newInstance(Role.class);
      // BeanPropertyRowMapper이용해서 DB에서 가져온 컬럼의 값을 자동으로 DTO(Role)에 담아준다.
      // java에서는 컬럼명을 카멜케이싱으로, db에서는 _로 단어구분을 함
    
      // RoleDao 생성자
      // 컨테이너가 dataSource를 주입해주기 때문에 이렇게 파라미터로 사용할 수 있다.
      // 컨테이너는 기본 생성자가 없는 객체를 주입해준다!
      public RoleDao(DataSource dataSource) {
        this.jdbc = new NamedParameterJdbcTemplate(dataSource);
        this.insertAction = new SimpleJdbcInsert(dataSource).withTableName("role");
      }
    
      // NamedParameterJdbcTemplate를 사용하여 모든 Role들을 가져온다.
      // RoleDaoSqls에 작성해준 SQL문을 사용한다.
      public List<Role> selectAll() {
        // SQL문, Collections.emptyMap()은 바인딩 값 전달을 위해 필요, rowMapper는 select 결과를 dto에 저장하기 위함.
        return jdbc.query(SELECT_ALL, Collections.emptyMap(), rowMapper);
      }
    
      // SimpleJdbcInsert을 사용한다.
      // params : <role 객체의 카멜케이싱 컬럼명, DB 속성명> Map 객체, 이걸  insertAction에  파라미터로 넣어서 insert 실행
      public int insert(Role role) {
        SqlParameterSource params = new BeanPropertySqlParameterSource(role);
        return insertAction.execute(params);
      }
    
      // insert랑 비슷하다.
      public int update(Role role) {
        SqlParameterSource params = new BeanPropertySqlParameterSource(role);
        return jdbc.update(UPDATE, params);
      }
    
      // roleId, role_id 이렇게 하나만 매핑하면 되기때문에 굳이 객체 전체를 매핑할 필요가 없으므로, 하나의 맵객체를 만들어서 파라미터로 넘겨준다. 
      public int deleteById(Integer id) {
        Map<String, ?> params = Collections.singletonMap("roleId", id);
        return jdbc.update(DELETE_BY_ROLE_ID, params);
      }
    
      public Role selectById(Integer id) {
        try {
          Map<String, ?> params = Collections.singletonMap("roleId", id);
          return jdbc.queryForObject(SELECT_BY_ROLE_ID, params, rowMapper);
        } catch (EmptyResultDataAccessException e) { //조건에 맞는 튜블이 없을 경우 예외처리.
          return null;
        }
      }
    
    }
    

     

    [참조]

    https://www.edwith.org/boostcourse-web/lecture/20660/

    'Web Development > 부스트코스 - Back-End(Java)' 카테고리의 다른 글

    [Back End] Layered Architecture and Rest Controller  (0) 2020.04.06
    [Back End] Spring MVC  (0) 2020.04.03
    [Back End] Spring Core  (0) 2020.03.25
    [Front End] Web UI development  (0) 2020.03.15
    [Back End] Web API  (0) 2020.03.14

    댓글

Designed by Tistory.