본문 바로가기

IT/SpringMVC

6. Spring JDBC 실습

@ 아래 내용은 https://www.edwith.org/boostcourse-web/ 사이트의 강의를 정리한 글 입니다. 


DTO란?

  • 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란?

  • DAO란 Data Access Object의 약자로 데이터를 조회하거나 조작하는 기능을 전담하도록 만든 객체입니다.
  • 보통 데이터베이스를 조작하는 기능을 전담하는 목적으로 만들어집니다.


ConnectionPool 이란?

  • DB연결은 비용이 많이 듭니다.
  • 커넥션 풀은 미리 커넥션을 여러 개 맺어 둡니다.
  • 커넥션이 필요하면 커넥션 풀에게 빌려서 사용한 후 반납합니다.
  • 커넥션을 반납하지 않으면 어떻게 될까요? // 커넥션을 빨리 반납하지 않으면 프로그램이 늦어지거나 장애가 발생할 수 있다. 
ConnectionPool

DataSource란?

  • DataSource는 커넥션 풀을 관리하는 목적으로 사용되는 객체입니다.
  • DataSource를 이용해 커넥션을 얻어오고 반납하는 등의 작업을 수행합니다.


Spring JDBC를 이용한 DAO작성 실습

Spring JDBC를 이용한 DAO작성 실습 

// 메이븐 프로젝트는 저번 처럼 같다 . 아키텍쳐는 퀵스타트 1.1 이다. 







실습코드

pom.xml

<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>
	<packaging>jar</packaging>

	<name>daoexam</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<spring.version>4.3.5.RELEASE</spring.version>
	</properties>

	<dependencies>
		<!-- Spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<!-- basic data source -->
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-dbcp2</artifactId>
			<version>2.1.1</version>
		</dependency>


		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.45</version>
		</dependency>

		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<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>
	</build>

</project>

 

ApplicationConfig.java // 설정에 관련된 부분 

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
@Import({DBConfig.class})
public class ApplicationConfig {

}

 // @Import 라는 어노테이션을 이용하면 설정파일을 여러개로 나눠서 작성 할 수 있다. 하나의 클래스가 모든 정보 갖고 있으면 유지 보수가 어렵다 . 

DBConfig.java

package kr.or.connect.daoexam.config;

import javax.sql.DataSource;

import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
public class DBConfig {
	private String driverClassName = "com.mysql.jdbc.Driver";
    private String url = "jdbc:mysql://localhost:3306/connectdb?useUnicode=true&characterEncoding=utf8";

    private String username = "connectuser";
    private String password = "connect123!@#";

    @Bean
    public DataSource dataSource() {
    	BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;

    }
}

// @EnableTransactionManagement 는 트랜잭션을 위한 것   일단 이정도만 알아두자 @Bean 사용해서 이미 등록되어있는 dataSource 객체 사용 

DataSourceTest.java

package kr.or.connect.daoexam.main;

import java.sql.Connection;

import javax.sql.DataSource;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import kr.or.connect.daoexam.config.ApplicationConfig;

public class DataSourceTest {

	public static void main(String[] args) {
		ApplicationContext ac = new AnnotationConfigApplicationContext(ApplicationConfig.class);
		DataSource ds = ac.getBean(DataSource.class);
		Connection conn = null;
		try {
			conn = ds.getConnection();
			if(conn != null)
				System.out.println("접속 성공^^");
		}catch (Exception e) {
			e.printStackTrace();
		}finally {
			if(conn != null) {
				try {
					conn.close();
				}catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

}

//접속성공 이라고 출력되면 된다.


실습코드

Role.java

package kr.or.connect.daoexam.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

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";
}

 //상수는 모든 글자를 대문자로 쓰는 것이 관례이다 이런 것은 잘지키자!

 두단어 이상일때 언더바로 단어를 구분한다 

RoleDao.java

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;
@Repository
public class RoleDao {
	private NamedParameterJdbcTemplate jdbc;
	private SimpleJdbcInsert insertAction;
	private RowMapper<Role> rowMapper = BeanPropertyRowMapper.newInstance(Role.class);

	public RoleDao(DataSource dataSource) {
		this.jdbc = new NamedParameterJdbcTemplate(dataSource);
		this.insertAction = new SimpleJdbcInsert(dataSource)
                .withTableName("role");
	}
	
	public List<Role> selectAll(){
		return jdbc.query(SELECT_ALL, Collections.emptyMap(), rowMapper);
	}

}

// 위에는 import static kr.or.connect.daoexam.dao.RoleDaoSqls.*; 가 빠져 있다 추가 해줘야된다...  

// DAO객체는 저장소에 역할을 한다는 의미로 @Repository 라는 어노테이션을 붙여 준다. 

// DataSource 는 생성된객체가 있기때문에  자동으로 주입된다. 

//static 임포트를 사용하면 변수를 클래스 이름 없이 바로 사용 할 수 있게 된다. 

//Collections.emptyMap() 이 들어간 자리는 바인딩 할 값을 전달할 목적으로 사용하고 있는 객체 이다. 

그런데 지금 없으니 빈맵객체를 전달 해주는 것.  

// 세번째 항목(rowMapper)은 셀렉트 한건 한건의 객체를 dto 저장하기 위한 목적으로 사용 culmn의 값을 자동으로 DTO에 담아주게 된다. 

결과가 여러건이었을때 내부적으로 반복하면 서 DTO를 생성하고 생성한DTO를 List에 다가 담아주는 일을 한다. 해당 List를 반환 해주게 된

다. 그리고 dbms 는 카멜 표기법을 쓰지 않고 언더바, 자바는 카멜표기법을 쓴다 그래서 둘의 이름이 달라서 힘든데 rowMapper 객체는 

자동으로 맞춰 준다. 흠. 

ApplicationConfig.java 

@ComponentScan(basePackages = { "kr.or.connect.daoexam.dao" })

 // 설정 파일을 읽도록 ComponentScan 사용 , 여러 패키지 쓸수 있다. 

SelectAllTest.java

package kr.or.connect.daoexam.main;

import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import kr.or.connect.daoexam.config.ApplicationConfig;
import kr.or.connect.daoexam.dao.RoleDao;
import kr.or.connect.daoexam.dto.Role;

public class SelectAllTest {

	public static void main(String[] args) {
		ApplicationContext ac = new AnnotationConfigApplicationContext(ApplicationConfig.class); 
		
		RoleDao roleDao =ac.getBean(RoleDao.class);

		List<Role> list = roleDao.selectAll();
		
		for(Role role: list) {
			System.out.println(role);
		}

	}

}



실습코드

RoleDaoSqls.java에 추가

public static final String UPDATE = "UPDATE role SET description = :description WHERE ROLE_ID = :roleId";

RoleDao.java

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;
@Repository
public class RoleDao {
	private NamedParameterJdbcTemplate jdbc;
	private SimpleJdbcInsert insertAction;
	private RowMapper<Role> rowMapper = BeanPropertyRowMapper.newInstance(Role.class);

	public RoleDao(DataSource dataSource) {
		this.jdbc = new NamedParameterJdbcTemplate(dataSource);
		this.insertAction = new SimpleJdbcInsert(dataSource)
                .withTableName("role");

	}
	
	public int insert(Role role) {
		SqlParameterSource params = new BeanPropertySqlParameterSource(role);
		return insertAction.execute(params);
	}

	public int update(Role role) {
		SqlParameterSource params = new BeanPropertySqlParameterSource(role);
		return jdbc.update(UPDATE, params);
	}
	

}

 // withTableName은 어떤 테이블에 넣을지 알려 주는 것.  

// BeanPropertySqlParameterSource(role)은 role 객체의 있는 값을 맵객체로 바꿔주는데 roleId를 role_id 등으로 자동으

로 바꿔 준다. 

//그리고 update 메소드에서는 params가 UPDATE 문장에 바인딩 시켜주는 역할을 한다. 

JDBCTest.java

package kr.or.connect.daoexam.main;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import kr.or.connect.daoexam.config.ApplicationConfig;
import kr.or.connect.daoexam.dao.RoleDao;
import kr.or.connect.daoexam.dto.Role;

public class JDBCTest {

	public static void main(String[] args) {
		ApplicationContext ac = new AnnotationConfigApplicationContext(ApplicationConfig.class);

		RoleDao roleDao = ac.getBean(RoleDao.class);
		
		Role role = new Role();
		role.setRoleId(201);
		role.setDescription("PROGRAMMER");
		
		int count = roleDao.insert(role);
		System.out.println(count + "건 입력하였습니다.");
			
		int count = roleDao.update(role);
		System.out.println(count +  " 건 수정하였습니다.");
	}

}

//insert 문 수행하면 int가 리턴 되는데 '한건 입력했습니다.' 이런 느낌이다 . 



실습코드

RoleDaoSqls.java에 추가

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";

// cloumn을 쓸때  * 를 쓰기도 하는데  ex) select*from role ; *보다 cloumn명 을 써주는게 더 이해하기 좋다. 

RoleDao.java에 추가

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;
@Repository
public class RoleDao {
	private NamedParameterJdbcTemplate jdbc;
	private SimpleJdbcInsert insertAction;
	private RowMapper<Role> rowMapper = BeanPropertyRowMapper.newInstance(Role.class);

	public RoleDao(DataSource dataSource) {
		this.jdbc = new NamedParameterJdbcTemplate(dataSource);
		this.insertAction = new SimpleJdbcInsert(dataSource)
                .withTableName("role");
	}
	
	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;
		}
	}

}

 // Delete 쿼리에도 update처럼 사용해도 되지만 한건만 넣어도 되는데 굳이 객체를 만들 필요 없기에 간단하게 하는 방법이 위에 방법이다. 

// select를 했는데 해당값이 없다면 exception이 발생하기에 적절한 exception 처리를 해줘야 한다. 


JDBCTest.java에 추가

Role resultRole = roleDao.selectById(201);
System.out.println(resultRole);
		
int deleteCount = roleDao.deleteById(500);
System.out.println(deleteCount + "건 삭제하였습니다.");
	
Role resultRole2 = roleDao.selectById(500);
System.out.println(resultRole2);
		

//delete도 int 값 리턴 한다.


'IT > SpringMVC' 카테고리의 다른 글

8. Spring MVC구성요소  (0) 2018.08.27
7. Spring MVC란?  (0) 2018.08.27
5. Spring JDBC 소개  (0) 2018.08.24
4. Java Config를 이용한 설정  (0) 2018.08.22
3. xml파일을 이용한 설정  (0) 2018.08.20