본문 바로가기

STUDY/스프링 철저 입문

2-1) 스프링 JDBC: DataSource, H2, SimpleJdbcInsert, NamedParameterJdbcTemplate, BeanPropertyRowMapper, BeanPropertySqlParameterSource

 - JAVA에서의 DB 접근: JDBC

 

거의 모든 서비스는 데이터를 기반으로 이루어진다. 따라서 DB에 접근하는 동작이 자주 수행되는데, JAVA에서는 이를 위해 JDBC가 존재한다. JDBC는 JAVA에서 각 데이터베이스에 접근하기위한 인터페이스이다.  실제 코드를 보면 다음과 같이 DB에 접근하여 데이터를 가져올 수 있다.

 

Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
  // 1. Connection을 가져오고
  conn = dataSource.getConnection();
  // 2. 쿼리를 실행할 준비를하고
  stmt = conn.prepareStatement("SELECT * FROM Noun001");
  // 3. 쿼리를 실행하고
  rs = stmt.executeQuery();
  // 4. 결과값을 처리하고
  while (rs.next()) {
    System.out.println(rs.getString(1));
    System.out.println(rs.getInt(2));
    System.out.println(rs.getString(3));
  }
} catch (Exception e) {
	e.printStackTrace();
} finally {
  try {
  // 5. Connection을 종료한다.
    if (conn != null)
    conn.close();
    if (stmt != null)
    stmt.close();
    if (rs != null)
    rs.close();
  } catch (SQLException e) {
    e.printStackTrace();
  }
}

 

JAVA의 JDBC를 사용한 DB 접근을 크게 5가지 동작으로 분류하여 주석을 달아두었다.

  1. DB에 대한 Connection을 DataSource에서 가져온다. 

  2. SQL을 실행을 위한 Statement를 준비 한다.

  3. 실제 쿼리를 실행한다.

  4. RuleSet에서 데이터를 추출한다. 

  5. 동작이 끝난 Connection, Statement, RuleSet을 close한다.

이 동작들은 DB에 접근하기 위해서는 항상 일어나야 하는 동작이다. 대부분의 동작이 크게 달라질 것이 없는 동작들이고, 개발자는 중복된 코드를 계속해서 작성할 수 밖에 없다. 하지만 스프링에서는 개발자가 의미있는 코드만을 작성할 수 있도록 도와주는 도구가 존재한다.

 

 

 - 스프링(Spring) JDBC

 

스프링 JDBC에서 Connection을 만들고 회수하는 동작, Statement를 만들고 회수하는 동작, 결과 값을 처리하는 동작 등 개발자가 해왔던 단순 반복적인 일들을 대신 해준다. 따라서 아래 코드를 보면 상당히 간단해진 것을 볼 수 있다.

 

NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
Map<String, Object> result =
	jdbcTemplate.queryForMap("SELECT * FROM Noun001", Collections.EMPTY_MAP);
System.out.println(result);

 

이제 개발자는 실행할 쿼리 문, 전달할 파라미터, 그리고 응답 값을 담을 객체만 준비하면 된다.  

 

 

 - 실습(환경 준비): maven, dataSource

 

스프링 JDBC를 실습하기 위해서 스프링 뿐 아니라, DataSource를 만들기 위한  commons-dbcp2 레포지토리, EmbeddedDB를 만들기 위한 h2 레포지토리를 pom.xml에 추가해야한다.

 

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>4.3.26.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-jdbc</artifactId>
  <version>4.3.26.RELEASE</version>
</dependency>
<dependency>
  <groupId>com.h2database</groupId>
  <artifactId>h2</artifactId>
  <version>1.4.200</version>
</dependency>
<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-dbcp2</artifactId>
  <version>2.6.0</version>
</dependency>

 

또 스프링 JDBC가 동작하려면 DataSource가 빈으로 등록되어 있어야 하므로, 스프링 설정에서 빈으로 등록해야한다. 여기서는 H2라는 EmbeddedDB에 대한 DataSource를 만들었다. 이를 위해서 resources 폴더에 schema.sql 파일을 생성하였다.

 

@Configuration
public class AppContextConfig {
  ...
  @Bean
  public DataSource dataSource() {
    DataSource dataSource = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2)
        .setScriptEncoding("UTF-8").addScript("classpath:schema.sql").build();
    return dataSource;
  }
  ...
}

 

// schema.sql 파일
CREATE TABLE Noun001 (
  sys_c VARCHAR(3) NOT NULL,
  id INT(11) NOT NULL AUTO_INCREMENT,
  value VARCHAR(20) NOT NULL,
  PRIMARY KEY (sys_c, id),
  UNIQUE INDEX id (id)
);

 

마지막으로 DataSource가 정상적으로 불러지는지 확인하면 준비는 끝난다.

 

public static void main(String[] args) {
  ...
  AnnotationConfigApplicationContext appContext =
  new AnnotationConfigApplicationContext(AppContextConfig.class);
  DataSource dataSource = appContext.getBean(DataSource.class);
  ...
}

 

 

 

 - 실습, 데이터 생성(Create): SimpleJdbcInsert

 

기존 JDBC로 id가 auto increment가 되어있는 테이블에 데이터를 넣고, 할당된 id를 받아오려면 별도의 동작이 필요했다. 하지만 스프링에서 제공하는 SimpleJdbcInsert를 사용하면 보다 편리하게 데이터를 넣고, id를 받아올 수 있다.

 

public static void main(String[] args) {
  ...
  SimpleJdbcInsert jdbcInsert = new SimpleJdbcInsert(dataSource).withTableName("Noun001")
      .usingColumns("sys_c", "value").usingGeneratedKeyColumns("id");
  Map<String, Object> param = new HashMap<String, Object>();
  param.put("sys_c", "000");
  param.put("value", "world");
  Integer key = jdbcInsert.executeAndReturnKey(param).intValue();
  System.out.println("key: " + key);
  ...
}
key: 1

 

SimpleJdbcInsert 객체를 만들고 withTableName 메소드에 어떤 테이블에 데이터를 삽입할지, usingColumns 메소드에 테이블의 어떤 칼럼을 이용할지, usingGeneratedKeyColumns 메소드에 어떤 칼럼을 자동으로 값을 받아올지 설정해주었다. map을 데이터 생성시 사용할 파라미터를 넣어주고 executeAndReturnKey 메소드를 호출하면, 테이블에 데이터가 삽입된다. 그리고 DB에서 받아온 기본키를 출력하고있다.

 

 

 - 실습, 데이터 읽기(Read): NamedParameterJdbcTemplate, BeanPropertyRowMapper

 

Spring JDBC의 NamedParameterJdbcTemplate를 사용하면, 굉장히 간단하게 DB를 조회할 수 있다. 

 

public static void main(String[] args) {
  ...
  NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
  ...
  List result = jdbcTemplate.queryForList("SELECT * FROM Noun001", Collections.EMPTY_MAP);
  System.out.println(result);
  ...
}
[{SYS_C=000, ID=1, VALUE=world}]

 

쿼리에 조건을 추가하고 싶다면 다음과 같이 SQL문을 바꾸고, 파라미터를 넣어주면 된다.

 

public static void main(String[] args) {
  ...
  NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
  ...
  Map<String, Object> param2 = new HashMap<String, Object>();
  param2.put("id", 1);
  List result = jdbcTemplate.queryForList("SELECT * FROM Noun001 WHERE id = :id", param2);
  System.out.println(result);
  ...
}

 

또, 해당 테이블을 위한 객체를 만들어서, 결과 값을 해당 객체에 담아서 받을 수 도 있다.

 

public class Noun001 {
  private String sysC;
  private Integer id;
  private String value;
  ...
}
public static void main(String[] args) {
  ...
  NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
  ...
  Map<String, Object> param2 = new HashMap<String, Object>();
  param2.put("id", 1);
  List<Noun001> result = jdbcTemplate.query("SELECT * FROM Noun001 WHERE id = :id", param2,
  BeanPropertyRowMapper.newInstance(Noun001.class));
  System.out.println(result);
  ...
}
[Noun001 [sysC=000, id=1, value=world]]

 

 

 - 실습, 데이터 수정(Update): NamedParameterJdbcTemplate, BeanPropertySqlParameterSource

 

스프링 JDBC를 사용하여 데이터 수정도 간단하게 할 수 있다.

 

public static void main(String[] args) {
  ...
  NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
  ...
  Noun001 noun001 = new Noun001();
  noun001.setId(1);
  noun001.setSysC("000");
  noun001.setValue("hello");
  SqlParameterSource param3 = new BeanPropertySqlParameterSource(noun001);
  Integer result = jdbcTemplate
      .update("UPDATE Noun001 SET sys_c = :sysC, value = :value WHERE id = :id", param3);
  System.out.println(result);
  ...
}

 

이처럼 BeanPropertySqlParameterSource를 활용하면 객체에서 바로 파라미터를 생성할 수 있다.

 

 

 - 실습, 데이터 삭제(Delete): NamedParameterJdbcTemplate, BeanPropertySqlParameterSource

 

데이터 삭제도 수정과 같은 방식으로 진행한다.

 

public static void main(String[] args) {
  ...
  NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
  ...
  Map<String, Object> param4 = new HashMap<String, Object>();
  param4.put("id", 1);
  Integer result = jdbcTemplate.update("DELETE FROM Noun001 WHERE id = :id", param4);
  System.out.println(result);
  ...
}

 

 - 마무리

 

최근 JAP나 MyBatis 같은 더욱 강력한 도구들이 나와있지만, 간단한 초기 설정과 낮은 학습비용 덕분에 여전히 JDBC를 사용하는 곳이 존재한다. 또 몰라서 못쓰는 것과, 알고 안쓰는 것은 분명히 다르다고 생각한다. 

728x90