스프링 JDBC

이지윤·2022년 4월 6일
0

스프링 JDBC

데이터 액세스 층

데이터 액세스 층의 역할

  • 데이터 액세스 처리를 비즈니스 로직 층에서 분리

DAO (Data Access Object)

  • 데이터 액세스 처리에 특화된 오브젝트

DAO 패턴

  • 데이터 취득, 변경에 데이터 처리를 DAO 오브젝트로 분리하는 패턴

자바의 데이터 액세스 기술

  • JDBC, Hybernate, MyBatis, JPA

DAO 구현에서 스프링의 역할

  • 데이터 액세스 기술을 쉽게 사용하기 위한 기능 제공

데이터 소스

  • 데이터 액세스 기술 종류 상관 X
  • 데이터베이스 접속을 관리해주는 인터페이스
  • 업무용 어플리케이션 -> 커넥션 풀에 의해 커넥션 오브젝트 재사용

데이터 소스 구현

  • 서드 파티가 제공하는 데이터 소스
    • Apache Commons DBCP
    • 의존 관계 설정
    • Bean 정의 파일레 DBCP 데이터 소스 설정

스프링 JDBC

JDBC 이용의 문제점

  • 대량의 소스 코드를 기술
  • 다양한 에러 원인을 파악하기 위한 코딩 필요
  • DB 제품마다 에러코드가 다름 -> 코드의 일관성 유지 어려움

스프링 JDBC

  • JDBC를 래핑한 API 제공 -> 소스 코드 단순화
  • JDBC를 직접 사용할 때 발생하는 장황한 코드 은닉

스프링 JDBC가 제공하는 중요 탬플릿

  • JdbcTemplate
  • NamedParameterTemplate

JdbcTemplate 클래스 제공 메서드

  • queryForObject : 하나의 결과 레코드 중에서 하나의 컬럼 값을 가져옴
  • queryForMap : 하나의 결과 레코드 정보를 Map 형태로 매핑
  • queryForList : 여러 개의 Map 형태의 결과 레코드 다룸
  • query : 여러 개의 레코드를 객체로 변환 후 처리
  • update : 데이터의 변경 (insert, update, delete)

템플릿 클래스의 오브젝트 생성과 인젝션

  • 템플릿 클래스를 XML 파일에 Bean으로 정의
  • applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:c="http://www.springframework.org/schema/c"
	xmlns:jdbc="http://www.springframework.org/schema/jdbc"
	xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
		
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
	    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
	    <property name="url" value="jdbc:mysql://127.0.0.1:3306/springdb?allowPublicKeyRetrieval=true&amp;useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=false&amp;serverTimezone=UTC" />
	    <property name="username" value="spring" />
	    <property name="password" value="12345" />
		<property name="maxActive" value="5" />
	</bean>    
		
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<constructor-arg ref="dataSource" />
	</bean>
	
	<context:component-scan base-package="org.tukorea.di.persistance"></context:component-scan>
	<context:component-scan base-package="org.tukorea.di.service"></context:component-scan>
 
</beans>

Select문

  • 취득 결과가 레코드 건수 or 특정 컬럼

    • queryForObject
      • 제 1인수 - sql문
      • 제 2인수 - 반환형 클래스 오브젝트
        JdbcTemplate jdbcTemplate = ctx.getBean(JdbcTemplate.class); int count = jdbcTemplate.queryForObject(
        "SELECT COUNT(*) FROM STUDENT", Integer.class);
    • queryForObject
      • 제 1인수 - sql문
      • 제 2인수 - 반환형 클래스 오브젝트
      • 제 3인수 - 파라미터 값
        String name = jdbcTemplate.queryForObject(
        "SELECT username FROM STUDENT WHERE id= ?", String.class, id);
  • 취득 결과가 한 레코드 값

    • queryForMap
      Map<String, Object> student = jdbcTemplate.queryForMap( "SELECT * FROM STUDENT WHERE id= ?", id);
      String name = (String)student.get("username");
    • queryForList
      List<Map<String, Object>> studentList = jdbcTemplate.queryForMap( "SELECT * FROM STUDENT ");
  • 도메인으로 변환

    • queryForObject 메서드와 query 메서드를 이용
      • queryForObject 메서드 – 한 레코드를 가져올 때
      • 제1인수 : SELECT 문
      • 제2인수 : 도메인 자동 변환을 위한 스프링 제공 클래스 (BeanPropertyRowMapper)
      • 제3인수 : SELECT 문의 파라미터
      • BeanPropertyRowMapper를 사용할 경우 StudentVO의 프로퍼티 명과 테이블 컬럼 명이 같아야 함.
      • 그렇지 않을 경우는 RoWMapper 인터페이스를 구현해서 StudentVO로 변환 처리
        public StudentVO read(String id) throws Exception { StudentVO vo = null;
        try {
        vo = jdbcTemplate.queryForObject(
        "SELECT * FROM STUDENT WHERE ID=?"
        , new BeanPropertyRowMapper<StudentVO>(StudentVO.class), id);
        }
        catch(EmptyResultDataAccessException e) {
        return vo; }
        return vo; }
    • qquery 메서드 – 여러 레코드를 가져올 때
      • RowMapper 인터페이스를 구현한 익명 클래스를 정의
      • 클래스내 mapRow() 추상 메서드를 정의
        public List<StudentVO> readList() throws Exception { List<StudentVO> studentlist = jdbcTemplate.query(
        "SELECT * FROM STUDENT",
        new RowMapper<StudentVO>() {
        } );
        public StudentVO mapRow(ResultSet rs, int rowNum) throws SQLException { StudentVO vo = new StudentVO();
        vo.setId(rs.getString("ID"));
        vo.setPasswd(rs.getString("PASSWD")); vo.setUsername(rs.getString("USERNAME")); vo.setSnum(rs.getString("SNUM")); vo.setDepart(rs.getString("DEPART")); vo.setMobile(rs.getString("MOBILE")); vo.setEmail(rs.getString("EMAIL"));
        return vo; }
        return studentlist; }

    Insert/ Update/ Delete문

    • update 메서드만을 사용

      Insert 문

      StudentVO vo; jdbcTemplate.update(
      "INSERT INTO STUDENT (ID, PASSWD, USERNAME, SNUM, DEPART, MOBILE, EMAIL) VALUES (?, ?, ?, ?, ?, ?, ?) " , vo.getId(), vo.getPasswd(), vo.getUsername(), vo.getSnum(), vo.getDepart(), vo.getMobile(), vo.getEmail()
      );

      Delete 문

      StudentVO vo;
      jdbcTemplate.update( “DELETE FROM STUDENT WHERE ID=?, vo.getId() );

db-springjdbc 예제 프로젝트

db-springjdbc 예제 구성

  • applicationContext.xml -> 네임스페이스 추가 (beans, context, c, jdbc)

POM.XML 추가 설정

  • pom.xml
    <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${org.springframework-version}</version>
    </dependency> <dependency>
    <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version>
    </dependency> <dependency>
    <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.28</version>
    </dependency>

MemberDAO.java

package org.tukorea.di.persistance;

import java.util.List;

import org.tukorea.di.domain.StudentVO;

public interface MemberDAO {
	public void add(StudentVO student) throws Exception;
	public StudentVO read(String id) throws Exception;
	public List<StudentVO> readList() throws Exception;

}

MemberDAOImpl.java

package org.tukorea.di.persistance;

import java.util.List;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.tukorea.di.domain.StudentVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Component;

@Component
public class MemberDAOImpl implements MemberDAO {

	@Autowired
	JdbcTemplate jdbcTemplate;
	
	// BeanPropertyRowMapper를 사용할 경우 StudentVO 의 프로퍼티 명과 테이블 컬럼 명이 같아야 함
	// 그렇지 않을 경우는 RoWMapper 인터페이스를 구현해서 레코드를 StudentVO로 변환 처리
	public StudentVO read(String id) throws Exception {
	
		StudentVO vo = null;
		try {
			vo = jdbcTemplate.queryForObject( 
				     "SELECT * FROM STUDENT WHERE ID=?"
		             , new BeanPropertyRowMapper<StudentVO>(StudentVO.class), id);
		}
		catch(EmptyResultDataAccessException e) {
			return vo;
		}
		return vo;   
	}
	
	// RoWMapper 인터페이스를 구현한 익명 클래스를 정의, 클래스내 mapRow() 추상 메서드를 정의 
	public List<StudentVO> readList() throws Exception {
		List<StudentVO> studentlist = jdbcTemplate.query( 
		     "SELECT * FROM STUDENT", 
		     	new RowMapper<StudentVO>() {
		    	 	public StudentVO mapRow(ResultSet rs, int rowNum) throws SQLException {
		    	 		StudentVO vo = new StudentVO();
		    	 		vo.setId(rs.getString("ID"));
		    	 		vo.setPasswd(rs.getString("PASSWD"));
		    	 		vo.setUsername(rs.getString("USERNAME"));
		    	 		vo.setSnum(rs.getString("SNUM"));
		    	 		vo.setDepart(rs.getString("DEPART"));
		    	 		vo.setMobile(rs.getString("MOBILE"));
		    	 		vo.setEmail(rs.getString("EMAIL"));
		    	 		return vo;
		    	 	}
           	}
		);
		return studentlist;
	}
	
	public void add(StudentVO vo) throws Exception {
		jdbcTemplate.update(
			"INSERT INTO STUDENT (ID, PASSWD, USERNAME, SNUM, DEPART, MOBILE, EMAIL) VALUES (?, ?, ?, ?, ?, ?, ?)"
			, vo.getId(), vo.getPasswd(), vo.getUsername(), vo.getSnum(), vo.getDepart(), vo.getMobile(), vo.getEmail());
	}
}

MemberService.java

package org.tukorea.di.service;

import java.util.List;

import org.tukorea.di.domain.StudentVO;

public interface MemberService {
	public StudentVO readMember(String id) throws Exception;
	public void addMember(StudentVO student) throws Exception;
	public List<StudentVO> readMemberList() throws Exception;

}

MemberServiceImpl.java

package org.tukorea.di.service;

import java.util.List;

import org.tukorea.di.domain.StudentVO;
import org.tukorea.di.persistance.MemberDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component

public class MemberServiceImpl implements MemberService {
	
	@Autowired
	private MemberDAO memberDAO;

	public StudentVO readMember(String id) throws Exception {
		return memberDAO.read(id);
	}
	
	public void addMember(StudentVO student) throws Exception {
		memberDAO.add(student);
	}
	
	public List<StudentVO> readMemberList() throws Exception{
		return memberDAO.readList();
	}
}

applicationContext.xml

  <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:c="http://www.springframework.org/schema/c"
	xmlns:jdbc="http://www.springframework.org/schema/jdbc"
	xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
		
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
	    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
	    <property name="url" value="jdbc:mysql://127.0.0.1:3306/springdb?allowPublicKeyRetrieval=true&amp;useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=false&amp;serverTimezone=UTC" />
	    <property name="username" value="spring" />
	    <property name="password" value="12345" />
		<property name="maxActive" value="5" />
	</bean>    
		
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<constructor-arg ref="dataSource" />
	</bean>
	
	<context:component-scan base-package="org.tukorea.di.persistance"></context:component-scan>
	<context:component-scan base-package="org.tukorea.di.service"></context:component-scan>
 
</beans>

MemberSampleMain.java

  
package org.tukorea.di.main;

import java.util.List;

import org.tukorea.di.domain.StudentVO;
import org.tukorea.di.service.MemberService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
//import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;


public class MemberSampleMain {

	private static ApplicationContext ctx = null;
	
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		System.out.println("안녕하세요 DB-SPRINGJDBC");

		ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		MemberService memberService = ctx.getBean(MemberService.class);  // by Class name
		
		String strID = "hansol";
		StudentVO vo = new StudentVO(); 
		vo.setId(strID); 
		vo.setPasswd(strID);  
		vo.setUsername(strID); 
		vo.setSnum(strID);
		
		try {
//			memberService.addMember(vo);
			StudentVO member = memberService.readMember(strID);
			System.out.println(member);
			
			List<StudentVO> list = memberService.readMemberList();
			for(StudentVO svo : list) {
				System.out.println(svo);
				
			}

		} catch(DataAccessException e) {
			System.out.println(e);
			
		} finally {  //Check Count  
			JdbcTemplate jdbcTemplate = ctx.getBean(JdbcTemplate.class);
			int count = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM STUDENT", Integer.class);
			System.out.println(count);
		}	
	}
}
profile
초보자

0개의 댓글