Bibi's DevLog ๐Ÿค“๐ŸŽ

[Spring] Spring JdbcTemplate ๊ฐ€์ด๋“œ (๊ณต์‹๋ฌธ์„œ, Baeldung) ๋ณธ๋ฌธ

๐Ÿ–ฅ BE ๋ฐฑ์—”๋“œ/Spring ์Šคํ”„๋ง

[Spring] Spring JdbcTemplate ๊ฐ€์ด๋“œ (๊ณต์‹๋ฌธ์„œ, Baeldung)

๋น„๋น„ bibi 2021. 5. 23. 22:53

Spring JdbcTemplate์— ๋Œ€ํ•œ ๊ณต์‹๋ฌธ์„œ ๊ฐ€์ด๋“œ

(K๊ฐ€ ์•Œ๋ ค์ฃผ์…จ๋‹ค๐Ÿ™‡โ€โ™€๏ธ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!)

3.1 Choosing an Approach for JDBC Database Access์—์„œ ๊ฐ„๋‹จํ•œ ์„ค๋ช…์„ ์ฝ๊ณ 

3.3.1. UsingJdbcTemplate ๋ถ€๋ถ„๋ถ€ํ„ฐ ๋ณด๋ฉด ๋  ๋“ฏ!

https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#jdbc

3.1 Choosing an Approach for JDBC Database Access (JDBC ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋Œ€ํ•œ ์ ‘๊ทผ๋ฐฉ์‹ ์„ ํƒ)

JdbcTemplate, SimpleJdbcInsert, SimpleJdbcCall, ๋“ฑ๋“ฑ์˜ ๋ฐฉ์‹๋“ค์ด JDBC ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ ‘๊ทผ์„ ์‰ฝ๊ฒŒ ํ•œ๋‹ค.

์…‹ ์ค‘ ํ•˜๋‚˜๋ฅผ ๊ณจ๋ผ ์“ฐ๋”๋ผ๋„, ๋‚˜๋จธ์ง€ ๋ฐฉ์‹์„ ์„ž์–ด ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

  • JdbcTemplate : ๊ธฐ๋ณธ์ ์ด๋ฉฐ ๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ๋Š” ์Šคํ”„๋ง JDBC ์ ‘๊ทผ๋ฒ•. ๊ฐ€์žฅ ๋‚ฎ์€ ์ˆ˜์ค€์˜ ์ ‘๊ทผ.
    • ๋‚˜๋จธ์ง€ ๋ฐฉ์‹๋“ค์€ ๋ชจ๋‘ ์ด ๋ฐฉ์‹์˜ ํ™•์žฅ์ด๋‹ค.
  • NamedParameterJdbcTemplate : JDBC์˜ ?๋ฐฉ์‹ ๋Œ€์‹  ๋ช…๋ช…๋œ ๋งค๊ฐœ๋ณ€์ˆ˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•จ. SQL๋ฌธ์— ์—ฌ๋Ÿฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์„ ๋•Œ ์œ ์šฉํ•จ.
  • SimpleJdbcInsert, SimpleJdbcCall : ํ•„์š”ํ•œ ๊ตฌ์„ฑ์˜ ๊ทœ๋ชจ๋ฅผ ์ œํ•œํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์ตœ์ ํ™”ํ•œ๋‹ค.

3.3.1 Using JdbcTemplate

JdbcTemplate๋Š” JDBC ์ฝ”์–ด ํŒจํ‚ค์ง€์˜ ์ค‘์‹ฌ ํด๋ž˜์Šค์ด๋‹ค.

  • ์ž์›์˜ ์ƒ์„ฑ ๋ฐ ๋ฆด๋ฆฌ์Šค๋ฅผ ๋‹ค๋ฃฌ๋‹ค.
  • JDBC์˜ ์ค‘์‹ฌ ์›Œํฌํ”Œ๋กœ์šฐ์˜ ๊ธฐ๋ณธ ์ž‘์—…์„ ๋‹ค๋ฃฌ๋‹ค.

JdbcTemplateํด๋ž˜์Šค๋Š”..

  • SQL์ฟผ๋ฆฌ๋“ค์„ ์‹คํ–‰ํ•จ
  • ๊ตฌ๋ฌธ๊ณผ ์ €์žฅ๋œ ํ”„๋กœ์‹œ์ € ํ˜ธ์ถœ์„ ์ˆ˜์ •ํ•จ
  • ResultSet ์ธ์Šคํ„ด์Šค์— ๋Œ€ํ•œ ๋ฐ˜๋ณต์„ ์‹คํ–‰ํ•จ
  • ๋ฐ˜ํ™˜๋œ ๋งค๊ฐœ๋ณ€์ˆ˜ ๊ฐ’์„ ์ถ”์ถœํ•จ
  • JDBC ์˜ˆ์™ธ๋ฅผ ์žก์•„ ๋” ์ผ๋ฐ˜์ ์ด๊ณ  ์œ ์ตํ•˜๊ฒŒ ๋ณ€ํ™˜ํ•จ

โ€ป DataSource๋Š” ํ•ญ์ƒ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์—์„œ ๋นˆ์œผ๋กœ ๊ตฌ์„ฑํ•ด์•ผ ํ•จ.

SELECT ์ฟผ๋ฆฌ

  • String์„ ์ฐพ๋Š” ์ฟผ๋ฆฌ

    • id๊ฐ€ 1212์ธ ๋ฐฐ์šฐ์˜ ์„ฑ์„ ๊ฐ€์ ธ์˜ด
    • String lastName = this.jdbcTemplate.queryForObject(
              "select last_name from t_actor where id = ?",
              String.class, 1212L);
  • ๋ฐ”์ธ๋“œ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ฟผ๋ฆฌ

    • ์ด๋ฆ„์ด Joe์ธ ๋ฐฐ์šฐ์˜ ์ˆ˜๋ฅผ ์…ˆ
    • int countOfActorsNamedJoe = this.jdbcTemplate.queryForObject(
              "select count(*) from t_actor where first_name = ?", Integer.class, "Joe");
  • ๊ด€๊ณ„์žˆ๋Š” ํ–‰(row)์˜ ์ˆ˜๋ฅผ ์„ธ๋Š” ์ฟผ๋ฆฌ

    • ๋ฐฐ์šฐ์˜ ์ˆ˜๋ฅผ ์…ˆ?
    • int rowCount = this.jdbcTemplate.queryForObject("select count(*) from t_actor", Integer.class);
  • ํ•˜๋‚˜์˜ ๋„๋ฉ”์ธ ๊ฐ์ฒด๋ฅผ ์ฐพ์•„์„œ ๊ฐ’์„ ์ฑ„์šฐ๋Š” ์ฟผ๋ฆฌ

    • ์•„์ด๋””๊ฐ€ 1212์ธ ๋ฐฐ์šฐ์˜ ์„ฑ๊ณผ ์ด๋ฆ„์„ ์ฐพ์Œ
    • Actor actor = jdbcTemplate.queryForObject(
              "select first_name, last_name from t_actor where id = ?",
              (resultSet, rowNum) -> {
                  Actor newActor = new Actor();
                  newActor.setFirstName(resultSet.getString("first_name"));
                  newActor.setLastName(resultSet.getString("last_name"));
                  return newActor;
              },
              1212L);
  • ์—ฌ๋Ÿฌ ๋„๋ฉ”์ธ ๊ฐ์ฒด(๋ฆฌ์ŠคํŠธ)๋ฅผ ์ฐพ์•„์„œ ๊ฐ’์„ ์ฑ„์šฐ๋Š” ์ฟผ๋ฆฌ

    • ๋ฐฐ์šฐ๋“ค์˜ ์„ฑ๊ณผ ์ด๋ฆ„์„ ์ฐพ์Œ
    • List<Actor> actors = this.jdbcTemplate.query(
              "select first_name, last_name from t_actor",
              (resultSet, rowNum) -> {
                  Actor actor = new Actor();
                  actor.setFirstName(resultSet.getString("first_name"));
                  actor.setLastName(resultSet.getString("last_name"));
                  return actor;
              });
  • ํ•˜๋‚˜์˜ ๋„๋ฉ”์ธ ๊ฐ์ฒด & ์—ฌ๋Ÿฌ ๋„๋ฉ”์ธ ๊ฐ์ฒด ๋ฅผ ์ฐพ์„ ๋•Œ RowMapper ์ฝ”๋“œ๊ฐ€ ์ค‘๋ณต๋˜๋Š” ๊ฒฝ์šฐ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ค‘๋ณต์„ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ๋‹ค

    • private final RowMapper<Actor> actorRowMapper = (resultSet, rowNum) -> {
          Actor actor = new Actor();
          actor.setFirstName(resultSet.getString("first_name"));
          actor.setLastName(resultSet.getString("last_name"));
          return actor;
      };
      
      public List<Actor> findAllActors() {
          return this.jdbcTemplate.query( "select first_name, last_name from t_actor", actorRowMapper);
      }

INSERT, UPDATE, DELETE ์ฟผ๋ฆฌ ๊ทธ๋ฆฌ๊ณ  JdbcTemplate

update(...) ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด INSERT, UPDATE, DELETE๋ฅผ ๋ชจ๋‘ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋งค๊ฐœ๋ณ€์ˆ˜ ๊ฐ’์€ ๋ณดํ†ต ๋ณ€์ˆ˜ / ๊ฐ์ฒด ๋ฐฐ์—ด๋กœ ์ œ๊ณต๋œ๋‹ค.

  • ์ƒˆ ์—”ํŠธ๋ฆฌ๋ฅผ ์‚ฝ์ž…ํ•˜๋Š” ์ฟผ๋ฆฌ

    • ์„ฑ์ด Watling, ์ด๋ฆ„์ด Leonor์ธ ๋ฐฐ์šฐ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค
    • this.jdbcTemplate.update(
              "insert into t_actor (first_name, last_name) values (?, ?)",
              "Leonor", "Watling");
  • ๊ธฐ์กด ์—”ํŠธ๋ฆฌ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ์ฟผ๋ฆฌ

    • id๊ฐ€ 5276์ธ ๋ฐฐ์šฐ์˜ ์ด๋ฆ„์„ Banjo๋กœ ์ˆ˜์ •ํ•œ๋‹ค
    • this.jdbcTemplate.update(
              "update t_actor set last_name = ? where id = ?",
              "Banjo", 5276L);
  • ๊ธฐ์กด ์—”ํŠธ๋ฆฌ๋ฅผ ์‚ญ์ œํ•˜๋Š” ์ฟผ๋ฆฌ

    • id๊ฐ€ actorId์ธ ๋ฐฐ์šฐ๋ฅผ ์‚ญ์ œํ•œ๋‹ค
    • this.jdbcTemplate.update(
              "delete from t_actor where id = ?",
              Long.valueOf(actorId));

JdbcTemplate ๋ชจ๋ฒ” ์‚ฌ๋ก€

์•„๋ž˜์™€ ๊ฐ™์ด DataSource๋Š” ์„ค์ • ํŒŒ์ผ์—์„œ ์ƒ์„ฑํ•˜๊ณ (Spring Configuration), ๊ทธ ๋นˆ์„ DAOํด๋ž˜์Šค์— ์˜์กด์„ฑ ์ฃผ์ž…ํ•˜๋Š” ๋ฐฉ์‹์ด ๊ถŒ์žฅ๋œ๋‹ค.

  • DAO ํด๋ž˜์Šค
  • public class JdbcCorporateEventDao implements CorporateEventDao { private JdbcTemplate jdbcTemplate; public void setDataSource(DataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource); } // JDBC-backed implementations of the methods on the CorporateEventDao follow... }
  • ์„ค์ • ํŒŒ์ผ (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" xsi:schemaLocation=" http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <bean id="corporateEventDao" class="com.example.JdbcCorporateEventDao"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <context:property-placeholder location="jdbc.properties"/> </beans>

๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ปดํฌ๋„ŒํŠธ์Šค์บ”๊ณผ ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

  • DAO ํด๋ž˜์Šค
  • @Repository public class JdbcCorporateEventDao implements CorporateEventDao { private JdbcTemplate jdbcTemplate; @Autowired public void setDataSource(DataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource); } // JDBC-backed implementations of the methods on the CorporateEventDao follow... }
  • ์„ค์ • ํŒŒ์ผ (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" xsi:schemaLocation=" http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- Scans within the base package of the application for @Component classes to configure as beans --> <context:component-scan base-package="org.springframework.docs.test" /> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <context:property-placeholder location="jdbc.properties"/> </beans>

3.3.2 Using NamedParameterJdbcTemplate

NamedParameterJdbcTemplate ํด๋ž˜์Šค๋Š” JDBC ๊ตฌ๋ฌธ์— ๋ช…๋ช…๋œ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•ด ์ค€๋‹ค.

๊ธฐ์กด JDBC๊ตฌ๋ฌธ๊ณผ ๋‹ค๋ฅธ ์ ์€ ?๋งŒ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ •์˜ํ•œ ๋งค๊ฐœ๋ณ€์ˆ˜๋ช…์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

์ด ํด๋ž˜์Šค๋Š” JdbcTemplate๋ฅผ ํฌํ•จํ•œ๋‹ค.

๋ช…๋ช…๋œ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด JDBC๊ตฌ๋ฌธ์„ ํ”„๋กœ๊ทธ๋ž˜๋ฐํ•  ๋•Œ ์ด ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

// some JDBC-backed DAO class...
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

public void setDataSource(DataSource dataSource) {
    this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}

public int countOfActorsByFirstName(String firstName) {

    String sql = "select count(*) from T_ACTOR where first_name = :first_name";

    SqlParameterSource namedParameters = new MapSqlParameterSource("first_name", firstName);

    return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class);
}

๋˜๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด, Map ๊ธฐ๋ฐ˜์œผ๋กœ ๋ช…๋ช…๋œ ๋งค๊ฐœ๋ณ€์ˆ˜์™€ ๊ทธ์— ์ƒ์‘ํ•˜๋Š” ๊ฐ’์„ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

// some JDBC-backed DAO class...
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

public void setDataSource(DataSource dataSource) {
    this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}

public int countOfActorsByFirstName(String firstName) {

    String sql = "select count(*) from T_ACTOR where first_name = :first_name";

    Map<String, String> namedParameters = Collections.singletonMap("first_name", firstName);

    return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters,  Integer.class);
}

NamedParameterJdbcTemplate์—๋Š” SqlParameterSource์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์กด์žฌํ•œ๋‹ค.

  • SqlParameterSource : NamedParameterJdbcTemplate์˜ ๋ช…๋ช…๋œ ๋งค๊ฐœ๋ณ€์ˆ˜์˜ source์ด๋‹ค.

  • MapSqlParameterSourceํด๋ž˜์Šค : java.util.Map์˜ ์–ด๋Œ‘ํ„ฐ(ํ‚ค๊ฐ€ ๋งค๊ฐœ๋ณ€์ˆ˜ ์ด๋ฆ„์ด๊ณ , ๊ฐ’์ด ๋งค๊ฐœ๋ณ€์ˆ˜ ๊ฐ’)์ธ ๊ฐ„๋‹จํ•œ ๊ตฌํ˜„์ฒด์ด๋‹ค.

  • BeanPropertySqlParameterSourceํด๋ž˜์Šค : ์ž„์˜์˜ ์ž๋ฐ”๋นˆ์„ ๋žฉํ•‘ํ•˜๊ณ , ๋žฉํ•‘๋œ ์ž๋ฐ”๋นˆ์˜ ์†์„ฑ์„ ๋ช…๋ช…๋œ ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ๊ฐ’์˜ source๋กœ ์‚ฌ์šฉํ•จ

  • ์˜ˆ์‹œ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

    • public class Actor {
      
          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;
          }
      
          // setters omitted...
      
      }
    • // some JDBC-backed DAO class...
      private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
      
      public void setDataSource(DataSource dataSource) {
          this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
      }
      
      public int countOfActors(Actor exampleActor) {
      
          // notice how the named parameters match the properties of the above 'Actor' class
          String sql = "select count(*) from T_ACTOR where first_name = :firstName and last_name = :lastName";
      
          SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(exampleActor);
      
          return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class);
      }

3.3.4 Running Statements

import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;

public class ExecuteAStatement {

    private JdbcTemplate jdbcTemplate;

    public void setDataSource(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

    public void doExecute() {
        this.jdbcTemplate.execute("create table mytable (id integer, name varchar(100))");
    }
}

3.3.5 Running Queries

  • queryForObject() : ํ•˜๋‚˜์˜ ๊ฐ’์„ ๋ฆฌํ„ดํ•  ๋•Œ (๊ฐฏ์ˆ˜๋ฅผ ์„ธ๊ฑฐ๋‚˜, ํ•œ ํ–‰์˜ ๊ฐ’์„ ๊ฒ€์ƒ‰ )

    • ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ int๋‚˜ String์„ ๋„ฃ์„ ์ˆ˜ ์žˆ๋‹ค

    • import javax.sql.DataSource;
      import org.springframework.jdbc.core.JdbcTemplate;
      
      public class RunAQuery {
      
          private JdbcTemplate jdbcTemplate;
      
          public void setDataSource(DataSource dataSource) {
              this.jdbcTemplate = new JdbcTemplate(dataSource);
          }
      
          public int getCount() {
              return this.jdbcTemplate.queryForObject("select count(*) from mytable", Integer.class);
          }
      
          public String getName() {
              return this.jdbcTemplate.queryForObject("select name from mytable", String.class);
          }
      }
  • queryForList() : ์—ฌ๋Ÿฌ ํ•ญ๋ชฉ์„ ๋ฆฌ์ŠคํŠธ๋กœ ๋ฆฌํ„ดํ•  ๋•Œ

    • private JdbcTemplate jdbcTemplate;
      
      public void setDataSource(DataSource dataSource) {
          this.jdbcTemplate = new JdbcTemplate(dataSource);
      }
      
      public List<Map<String, Object>> getList() {
          return this.jdbcTemplate.queryForList("select * from mytable");
      }
    • ๋ฆฌํ„ด๋˜๋Š” ๋ฆฌ์ŠคํŠธ์˜ ํ˜•ํƒœ๋Š” [{name=Bob, id=1}, {name=Mary, id=2}] ์™€ ๊ฐ™๋‹ค.

3.3.5. Updating the Database

  • ํŠน์ • PK์˜ ์ปฌ๋Ÿผ์„ ์ˆ˜์ •ํ•˜๋Š” ๊ฒฝ์šฐ์˜ ์˜ˆ์‹œ.

    • import javax.sql.DataSource;
      import org.springframework.jdbc.core.JdbcTemplate;
      
      public class ExecuteAnUpdate {
      
          private JdbcTemplate jdbcTemplate;
      
          public void setDataSource(DataSource dataSource) {
              this.jdbcTemplate = new JdbcTemplate(dataSource);
          }
      
          public void setName(int id, String name) {
              this.jdbcTemplate.update("update mytable set name = ? where id = ?", name, id);
          }
      }

Spring JDBC Template ํŠœํ† ๋ฆฌ์–ผ (Baeldung) (์ž‘์„ฑ ์ค‘)

์ถœ์ฒ˜ : https://www.baeldung.com/spring-jdbc-jdbctemplate

  • datasource ํŒจํ‚ค์ง€ : ๋ฐ์ดํ„ฐ ์†Œ์Šค์— ์•ก์„ธ์Šคํ•˜๊ธฐ ์œ„ํ•œ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค.

2. ๊ตฌ์„ฑ

๋ฐ์ดํ„ฐ ์†Œ์Šค์˜ ๊ฐ„๋‹จํ•œ ๊ตฌ์„ฑ. (MySQL ์‚ฌ์šฉ)

๋ฐ์ดํ„ฐ์†Œ์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋งŒ๋“ค๊ธฐ.

@Configuration
@ComponentScan("com.baeldung.jdbc")
public class SpringJdbcConfig {
    @Bean
    public DataSource mysqlDataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/springjdbc");
        dataSource.setUsername("guest_user");
        dataSource.setPassword("guest_password");

        return dataSource;
    }
}

3. JdbcTemplate ๋ฐ ์ฟผ๋ฆฌ ์‹คํ–‰

3.1. ๊ธฐ๋ณธ ์ฟผ๋ฆฌ

JdbcTemplate API๋กœ ์•„๋ž˜์™€ ๊ฐ™์€ ๋Œ€๋ถ€๋ถ„์˜ ๊ธฐ๋Šฅ์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ๋‹ค.

  • Connection ์ƒ์„ฑ ๋ฐ ์ข…๋ฃŒ
  • ๊ตฌ๋ฌธ ์‹คํ–‰ ๋ฐ ์ €์žฅ๋œ ์ ˆ์ฐจ ํ˜ธ์ถœ
  • ResultSet์„ ์ˆœํšŒํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜

๊ฐ„๋‹จํ•œ SELECT๋ฌธ

  • int result = jdbcTemplate.queryForObject(
        "SELECT COUNT(*) FROM EMPLOYEE", Integer.class);

๊ฐ„๋‹จํ•œ INSERT๋ฌธ

  • public int addEmplyee(int id) {
        return jdbcTemplate.update(
          "INSERT INTO EMPLOYEE VALUES (?, ?, ?, ?)", id, "Bill", "Gates", "USA");
    }
  • ?๋ฅผ ํ†ตํ•ด ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

3.2. ๋ช…๋ช…๋œ ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์žˆ๋Š” ์ฟผ๋ฆฌ

์ด๋ฆ„์ด ์žˆ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด NamedParameterJdbcTemplate๋ผ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

  • (?) ๋‚ด๋ถ€์ ์œผ๋กœ ?๋ฅผ ์ด๋ฆ„ ์žˆ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋Œ€์ฒดํ•˜๋ฉฐ, ์ฟผ๋ฆฌ ์‹คํ–‰์„ ์œ„ํ•ด ๊ฐ์‹ผ JdbcTemplate๋กœ ์œ„์ž„ํ•œ๋‹ค

๋ช…๋ช…๋œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์œ„ํ•œ ๊ฐ’์„ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด MapSqlParameterSource๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

  • SqlParameterSource namedParameters = new MapSqlParameterSource().addValue("id", 1);
    return namedParameterJdbcTemplate.queryForObject(
      "SELECT FIRST_NAME FROM EMPLOYEE WHERE ID = :id", namedParameters, String.class);

๋ช…๋ช…๋œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๊ฒฐ์ •์ง“๊ธฐ ์œ„ํ•ด ์Šคํ”„๋ง ๋นˆ์œผ๋กœ๋ถ€ํ„ฐ ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

  • Employee employee = new Employee();
    employee.setFirstName("James");
    
    String SELECT_BY_ID = "SELECT COUNT(*) FROM EMPLOYEE WHERE FIRST_NAME = :firstName";
    
    SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(employee);
    return namedParameterJdbcTemplate.queryForObject(
      SELECT_BY_ID, namedParameters, Integer.class);
  • BeanPropertySqlParameterSource๋ฅผ ์‚ฌ์šฉํ•œ ๊ตฌํ˜„ (์ „์ฒ˜๋Ÿผ ๋ช…๋ช…๋œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํŠน์ •ํ•˜๋Š” ๋Œ€์‹ )

3.3. Java ๊ฐ์ฒด์— ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ ๋งตํ•‘ํ•˜๊ธฐ

RowMapper์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•จ์œผ๋กœ์จ ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ์ž๋ฐ” ๊ฐ์ฒด์— ๋งตํ•‘ํ•  ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์ฟผ๋ฆฌ์— ์˜ํ•ด ๋ฐ˜ํ™˜๋˜๋Š” ๊ฐ ํ–‰์— ๋Œ€ํ•ด, ์Šคํ”„๋ง์ด row mapper๋ฅผ ์‚ฌ์šฉํ•ด ์ž๋ฐ” ๋นˆ์„ ์ฑ„์šด๋‹ค.

  • public class EmployeeRowMapper implements RowMapper<Employee> {
        @Override
        public Employee mapRow(ResultSet rs, int rowNum) throws SQLException {
            Employee employee = new Employee();
    
            employee.setId(rs.getInt("ID"));
            employee.setFirstName(rs.getString("FIRST_NAME"));
            employee.setLastName(rs.getString("LAST_NAME"));
            employee.setAddress(rs.getString("ADDRESS"));
    
            return employee;
        }
    }

๊ทธ ๋‹ค์Œ, row mapper๋ฅผ ์ฟผ๋ฆฌ API์— ์ „๋‹ฌํ•˜๊ณ  ์™„์ „ํžˆ ์ฑ„์›Œ์ง„ ์ž๋ฐ” ๊ฐ์ฒด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

  • String query = "SELECT * FROM EMPLOYEE WHERE ID = ?";
    Employee employee = jdbcTemplate.queryForObject(
      query, new Object[] { id }, new EmployeeRowMapper());