-
[Back End] Spring JDBCWeb Development/부스트코스 - Back-End(Java) 2020. 3. 30. 22:05
✔️ Spring JDBC
◾ JDBC를 이용해서 프로그래밍을 하게 되면 반복적인 코드가 많이 발생한다.
◾ 반복적인 코드는 개발자의 생산성을 떨어뜨리는 주된 원인이다.
◾ 반복적인 JDBC의 모든 저수준 세부사항을 Spring JDBC가 처리해준다.
◾ Spring JDBC를 사용하여 개발자는 필요한 부분만 개발하면 된다.
◾ Spring JDBC 외에 JPA, MyBatis 등의 기술들이 존재한다.
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 연결은 비용이 많이 든다.
◾ 커넥션 풀은 미리 커넥션을 여러개 맺어 둔다.
◾ 커넥션이 필요하면 커넥션 풀에게 커넥션을 빌리서 사용한 후 반납한다.
✔️ 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; } } }
[참조]
'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