# [JdbcTemplate] JdbcTemplate ์ ์šฉ
Study Repository

[JdbcTemplate] JdbcTemplate ์ ์šฉ

by rlaehddnd0422

SQL์„ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์— ์Šคํ”„๋ง์ด ์ œ๊ณตํ•˜๋Š” JdbcTemplate์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

 

JdbcTemplate ์žฅ์ 

  • ์„ค์ •์˜ ํŽธ๋ฆฌํ•จ
    • JdbcTemplate์€ spring-jdbc ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ํฌํ•จ๋˜์–ด, ๋ณ„๋„์˜ ๋ณต์žกํ•œ ์„ค์ • ์—†์ด ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • build.gradle ์— ์ถ”๊ฐ€๋งŒ ํ•˜๋ฉด ์‚ฌ์šฉ ๊ฐ€๋Šฅ 

      implementation 'org.springframework.boot:spring-boot-starter-jdbc' 

  • ๋ฐ˜๋ณต ๋ฌธ์ œ ํ•ด๊ฒฐ
    • JDBC๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•  ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ๋ฐ˜๋ณต์ ์ธ ์ž‘์—…์„ ๋Œ€์‹  ์ฒ˜๋ฆฌํ•ด ์ฃผ๋Š” ๋•๋ถ„์—, ๊ฐœ๋ฐœ์ž๋Š” SQL ์ž‘์„ฑ, ์ „๋‹ฌ ํŒŒ๋ผ๋ฏธํ„ฐ ์ •์˜, ์‘๋‹ต ๊ฐ’ ๋งคํ•‘๋งŒ ํ•˜๋ฉด ๋จ.
    • JdbcTemplate์€ ์ปค๋„ฅ์…˜ ํš๋“, statement ์ค€๋น„ ์‹คํ–‰, ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜๋ณตํ•˜๋„๋ก ๋ฃจํ”„๋ฅผ ์‹คํ–‰, ์ปค๋„ฅ์…˜-statement-resultset ์ข…๋ฃŒ, ํŠธ๋žœ์žญ์…˜์„ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•œ ์ปค๋„ฅ์…˜ ๋™๊ธฐํ™”, ์˜ˆ์™ธ ๋ฐœ์ƒ์‹œ ์Šคํ”„๋ง ์˜ˆ์™ธ ๋ณ€ํ™˜๊ธฐ ์‹คํ–‰ ์˜ ๋ฐ˜๋ณต์ž‘์—…์„ ๋Œ€์‹  ์ฒ˜๋ฆฌํ•ด์ค๋‹ˆ๋‹ค!

JdbcTemplate ๋‹จ์ 

  • ๋™์  SQL์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

JdbcTemplate 

Repository์— JdbcTemplate์„ ์ ์šฉํ•ด๋ณด๋ฉด์„œ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

Database :  H2 
Table : Item ( id(big int by default as identity, PK)  , item_name(varchar10) , price(int), quantity(int) ) 

 

์šฐ์„  JdbcTemplate์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” dataSource๋ฅผ ์ฃผ์ž…๋ฐ›์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. 

public JdbcTemplateItemRepositoryV1(DataSource dataSource)
{
    this.template = new JdbcTemplate(dataSource);
}

jdbctemplate.update() For insert, update, delete

jdbctemplate.update() arguments

 jdbctemplate.update(PreparedStatementCreator, KeyHolder)

  • DB์— ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฝ์ž…(insert) ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” update() ๋ฉ”์†Œ๋“œ์— PreparedStatementCreator , KeyHolder๋ฅผ ์ธ์ž๋กœ ๋ฐ›์Šต๋‹ˆ๋‹ค. 
  • update() ๋ฉ”์†Œ๋“œ์˜ ๋ฆฌํ„ด ๊ฐ’์€ ์˜ํ–ฅ ๋ฐ›์€ row ์ˆ˜ (int)
  • PreparedStatmentCreator์˜ createPreparedStatement๋Š” Connection์„ ์ธ์ž๋กœ ๋ฐ›์•„ PreparedStatment๋ฅผ ์ƒ์„ฑํ•ด์ฃผ๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
@FunctionalInterface
public interface PreparedStatementCreator {

   /**
    * Create a statement in this connection. Allows implementations to use
    * PreparedStatements. The JdbcTemplate will close the created statement.
    * @param con the connection used to create statement
    * @return a prepared statement
    * @throws SQLException there is no need to catch SQLExceptions
    * that may be thrown in the implementation of this method.
    * The JdbcTemplate class will handle them.
    */
   PreparedStatement createPreparedStatement(Connection con) throws SQLException;

}
  • ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅ(insert)ํ•  ๋•Œ Primary Key (PK) ์ƒ์„ฑ์— identity ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ Id๊ฐ’์€ ์ง์ ‘ ์ง€์ •ํ•˜์ง€ ์•Š๊ณ  ๋น„์›Œ๋‘๊ณ  ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  • PK์ธ ID ๊ฐ’์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ์ƒ์„ฑํ•˜๋ฏ€๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— insert๊ฐ€ ์™„๋ฃŒ๋œ ์ดํ›„์— ์ƒ์„ฑ๋œ PK ID ๊ฐ’์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • KeyHolder ์™€ connection.prepareStatement(sql, new String[]{"id"}) ๋ฅผ ์‚ฌ์šฉํ•ด์„œ id ๋ฅผ ์ง€์ •ํ•ด์ฃผ๋ฉด INSERT ์ฟผ๋ฆฌ ์‹คํ–‰ ์ดํ›„์— ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์ƒ์„ฑ๋œ ID ๊ฐ’์„ ์กฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์—ฌ๊ธฐ์„œ๋Š” PreparedStatementCreator์˜ createPreparedStatement๋ฅผ ๋žŒ๋‹ค์‹์œผ๋กœ ํ‘œํ˜„
    • ์ธ์ž๋กœ ๋ฐ›์€ connection์„ ํ†ตํ•ด pstmt ์„ธํŒ… ํ›„ ๋ฆฌํ„ด 
public Item save(Item item) {
    String sql = "insert into item(item_name,price,quantity) values(?,?,?)";
    KeyHolder keyHolder = new GeneratedKeyHolder();

    template.update(connection -> {
        // ์ž๋™ ์ฆ๊ฐ€ ํ‚ค
        PreparedStatement pstmt = connection.prepareStatement(sql, new String[]{"id"});
        pstmt.setString(1,item.getItemName());
        pstmt.setInt(2,item.getPrice());
        pstmt.setInt(3, item.getQuantity());
        return pstmt;
    }, keyHolder);

    long key = keyHolder.getKey().longValue();
    item.setId(key);

    return item;
}

jdbctemplate.update(sql, args..)

  • DB์— ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •,์‚ญ์ œ(update,delete) ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” update() ๋ฉ”์†Œ๋“œ์— sql, args..๋ฅผ ์ธ์ž๋กœ ๋ฐ›์Šต๋‹ˆ๋‹ค. 
  • args์—๋Š” sql์˜ ์ธ๋ฑ์Šค ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ์ž…๋ ฅ
@Override
public void update(Long itemId, ItemUpdateDto updateParam) {
    String sql = "update item set item_name=?, price=?, quantity=? where id = ?";
    template.update(sql,
            updateParam.getItemName(),
            updateParam.getPrice(),
            updateParam.getQuantity(),
            itemId);
}

 

jdbctemplate.queryForObject(),   jdbctemplate.query() For select

queryForObject() arguments
query() arguments

  • queryForObject() : ๊ฒฐ๊ณผ ๋กœ์šฐ๊ฐ€ ํ•˜๋‚˜์ธ ๊ฒฝ์šฐ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • query() : ๊ฒฐ๊ณผ ๋กœ์šฐ๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ์ธ ๊ฒฝ์šฐ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

queryForObject(sql, RowMapper, args) 

@Override
public Optional<Item> findById(Long id) {
    String sql = "select id, item_name, price, quantity from item where id=?";
    try
    {
        Item item = template.queryForObject(sql, itemRowMapper(), id);
        return Optional.of(item);
    }catch(EmptyResultDataAccessException e)
    {
        return Optional.empty();
    }
}
private RowMapper<Item> itemRowMapper() {
    return ( (rs, rowNum) -> {
        Item item = new Item();
        item.setId(rs.getLong("id"));
        item.setItemName(rs.getString("item_name"));
        item.setPrice(rs.getInt("price"));
        item.setQuantity(rs.getInt("quantity"));
        return item;
    });
}

  • ์—ฌ๊ธฐ์„œ RowMapper๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๋ฐ˜ํ™˜ ๊ฒฐ๊ณผ์ธ ResultSet์„ ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  • ItemRepository.findById() ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๊ฒฐ๊ณผ๊ฐ€ ์—†์„ ๋•Œ Optional ์„ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ๊ฒฐ๊ณผ๊ฐ€ ์—†์œผ๋ฉด ์˜ˆ์™ธ๋ฅผ ์žก์•„์„œ Optional.empty ๋ฅผ ๋Œ€์‹  ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์„ค์ •.

 

[JdbcTemplate] RowMapper์— ๋Œ€ํ•ด

jdbctemplate์—์„œ select๋Š” query()์™€ queryForObject() ๋ผ๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. query() ๋Š” ์ฟผ๋ฆฌ๋ฌธ ์‹คํ–‰์„ ํ†ตํ•ด ๊ฒฐ๊ณผ row๊ฐ€ ํ•˜๋‚˜์ผ ๊ฒฝ์šฐ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. queryForObject() ๋Š” ์ฟผ๋ฆฌ๋ฌธ ์‹คํ–‰์„ ํ†ตํ•ด ๊ฒฐ๊ณผ row๊ฐ€ ํ•˜๋‚˜ ์ด์ƒ

rlaehddnd0422.tistory.com

  • JDBC๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•  ๋•Œ๋Š” rs.next()๋กœ ๋ฃจํ”„๋ฅผ ์ง์ ‘ ๋Œ๋ ค์ฃผ์—ˆ์ง€๋งŒ, jdbctemplate์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฃจํ”„๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•  ํ•„์š” ์—†์ด ๋ฃจํ”„๋ฅผ ๋Œ๋ฆด ๋‚ด๋ถ€ ์ฝ”๋“œ๋งŒ ๊ตฌํ˜„ํ•ด์„œ ๋‚ด๋ถ€ ์ฝ”๋“œ๋งŒ ์ฑ„์šฐ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋ฃจํ”„๋Š” RowMapper๊ฐ€ ๋Œ๋ ค์ค๋‹ˆ๋‹ค. 
  • query()์€ queryForObject()์™€ ๋น„๊ตํ•ด ๊ฒฐ๊ณผ ๋กœ์šฐ๊ฐ€ ํ•œ ๊ฐœ ์ด์ƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ฆฌํ„ด๊ฐ’์ด List<T>๋ผ๋Š” ์ ์„ ์ œ์™ธํ•˜๊ณ ๋Š” ์ฐจ์ด์ ์ด ์—†์œผ๋ฏ€๋กœ ๋”ฐ๋กœ ์„ค๋ช…์€ ์ƒ๋žตํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

jdbctemplate์— ๋™์  SQL ์ ์šฉ 

item ํ…Œ์ด๋ธ”์— ์žˆ๋Š” ํŠน์ • rows๋ฅผ ๋‹ค์Œ ๋„ค ๊ฐ€์ง€ ์กฐ๊ฑด์œผ๋กœ ๊ฒ€์ƒ‰ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋™์  ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. 

 

1. ๊ฒ€์ƒ‰ ์กฐ๊ฑด์ด ์—†๋Š” ๊ฒฝ์šฐ 

select id, item_name, price, quantity from item

2. ์ƒํ’ˆ๋ช…๋งŒ์œผ๋กœ ๊ฒ€์ƒ‰

select id, item_name, price, quantity from item where item_name like concat('%',?,'%')

3. ์ตœ๋Œ€ ๊ฐ€๊ฒฉ๋งŒ์œผ๋กœ ๊ฒ€์ƒ‰

select id, item_name, price, quantity from item where price <= ?

4. ์ƒํ’ˆ๋ช…, ์ตœ๋Œ€ ๊ฐ€๊ฒฉ์œผ๋กœ ๊ฒ€์ƒ‰

select id, item_name, price, quantity from item
where item_name like concat('%',?,'%') and price <= ?

ํ•˜์ง€๋งŒ jdbctemplate์€ ๋”ฐ๋กœ ๋™์  ์ฟผ๋ฆฌ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์•„๋ž˜์™€ ๊ฐ™์ด ๊ตฌํ˜„ํ•ด ์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

@Override
public List<Item> findAll(ItemSearchCond cond) {
    String itemName = cond.getItemName();
    Integer maxPrice = cond.getMaxPrice();

    String sql = "select id, item_name, price, quantity from item";

    // jdbc ๋™์  ์ฟผ๋ฆฌ
    if (StringUtils.hasText(itemName) || maxPrice != null) {
        sql += " where";
    }

    boolean andFlag = false;
    List<Object> param = new ArrayList<>();

    if (StringUtils.hasText(itemName))
    {
    sql += " item_name like concat('%',?,'%')";
    param.add(itemName);
    andFlag = true;
    }

    if (maxPrice != null)
    {
        if (andFlag) {
          sql += " and";
        }
        sql += " price <= ?";
        param.add(maxPrice);
    }
    log.info("sql={}", sql);

    return template.query(sql, itemRowMapper(), param.toArray());
}

์ƒํ™ฉ์ด ์ปค์งˆ์ˆ˜๋ก ๋™์  ์ฟผ๋ฆฌ๋ฅผ ์ง์ ‘ ์ƒ์„ฑํ•˜๋Š” ์ผ์€ ๊ฝค ๋ณต์žกํ•œ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.

๋™์  ์ฟผ๋ฆฌ๋Š” MyBatis๋‚˜ querydsl์„ ์‚ฌ์šฉํ•˜๋ฉด ์‰ฝ๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

NamedParameterJdbcTemplate

jdbctemplate์„ ์‚ฌ์šฉํ•˜๋ฉด ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ๋ฐ”์ธ๋”ฉํ•ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

String sql = "update item set item_name=?, price=?, quantity=? where id = ?";
template.update(sql,
        updateParam.getItemName(),
        updateParam.getPrice(),
        updateParam.getQuantity(),
        itemId);

 

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

 

NamedParameterJdbcTemplate๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋‹น์—ฐํžˆ dataSource๋ฅผ ์ฃผ์ž…๋ฐ›์Šต๋‹ˆ๋‹ค.

public JdbcTemplateItemRepositoryV2(DataSource dataSource)
{
    this.template = new NamedParameterJdbcTemplate(dataSource);
}

 

 

NameParamterJdbcTemplate์€ update() ๋ฉ”์†Œ๋“œ์—์„œ ์•„๋ž˜ ์ธ์ž๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

NamedParameterJdbcTemplate update() arguments

ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Map์ฒ˜๋Ÿผ key, value ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค์–ด ์ „๋‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

์ด Map์„ ์ง์ ‘ ๋งŒ๋“ค์–ด ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ์ง€๋งŒ, SqlParameterSource๋ผ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

1. BeanPropertySqlParameterSource ( SqlParameterSource Interface ) 

@Override
public Item save(Item item) {
    String sql = "insert into item(item_name,price,quantity) "
            + "values (:itemName, :price, :quantity)";

    SqlParameterSource param = new BeanPropertySqlParameterSource(item);
    KeyHolder keyHolder = new GeneratedKeyHolder();

    template.update(sql, param, keyHolder);

    long key = keyHolder.getKey().longValue();
    item.setId(key);
    return item;
}

BeanPropertySqlParameterSource(T)

  • ํ•ด๋‹น Type์— ์ž๋ฐ”๋นˆ ํ”„๋กœํผํ‹ฐ ๊ทœ์•ฝ(getXxx() -> xxx)์„ ํ†ตํ•ด ์ž๋™์œผ๋กœ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  • ex) T์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ํ†ตํ•ด (key=itemName, value=๊ฐ’), (key=price, value = ๊ฐ’), (key=quantity, value = ๊ฐ’) ์ƒ์„ฑ

2. MapSqlParameterSource( SqlParameterSource Interface ) 

public void update(Long itemId, ItemUpdateDto updateParam) {
    String sql = "update item " +
            "set item_name=:itemName, price=:price, quantity=:quantity " +
            "where id=:id";

	// SqlParameterSource param = new MapSqlParameterSource("itemName",updateParam.getItemName());

    SqlParameterSource param = new MapSqlParameterSource()
            .addValue("itemName", updateParam.getItemName())
            .addValue("price", updateParam.getPrice())
            .addValue("quantity", updateParam.getQuantity())
            .addValue("id", itemId);

    template.update(sql, param);
}

 

MapSqlParameterSource()

  • ํŠน์ • T๋กœ๋ถ€ํ„ฐ ๋ฐ”์ธ๋”ฉํ•ด์•ผ ํ•  ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ๊ทธ ์™ธ์˜ ํƒ€์ž…๋„ ๋ฐ”์ธ๋”ฉ ํ•ด์•ผ ํ•  ๊ฒฝ์šฐ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • ์ถ”๊ฐ€๋กœ MapSqlParameterSource๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋“ฑ๋กํ•ด์•ผ ํ•  ๊ฒฝ์šฐ ์œ„์ฒ˜๋Ÿผ ๋ฉ”์†Œ๋“œ ์ฒด์ธ์„ ํ†ตํ•ด ํŽธ๋ฆฌํ•˜๊ฒŒ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

3. Map์„ ์ง์ ‘ ์‚ฌ์šฉ 

    @Override
    public Optional<Item> findById(Long id) {
        String sql = "select id, item_name, price, quantity from item where id=:id";
        try
        {
//            MapSqlParameterSource param = new MapSqlParameterSource("id", id);
            Map<String, Object> param = Map.of("id",id);
            Item item = template.queryForObject(sql, param, itemRowMapper());
            return Optional.of(item);
        }catch(EmptyResultDataAccessException e)
        {
            return Optional.empty();
        }
    }

    private RowMapper<Item> itemRowMapper() {

        return BeanPropertyRowMapper.newInstance(Item.class);

//        return ( (rs, rowNum) -> {
//            Item item = new Item();
//            item.setId(rs.getLong("id"));
//            item.setItemName(rs.getString("item_name"));
//            item.setPrice(rs.getInt("price"));
//            item.setQuantity(rs.getInt("quantity"));
//            return item;
//        });
    }
  • Map์„ ์ง์ ‘ ์‚ฌ์šฉํ•ด์„œ param ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด๋„ ๋ฉ๋‹ˆ๋‹ค.
* itemRowMapper()๋ฅผ BeanPropertyRowMapper.newInstance(Item.class)๋กœ ์ƒ์„ฑํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

Q. ๊ทธ๋ ‡๋‹ค๋ฉด ์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ•˜๋ฉด itemRowMapper()  setItemName()์ด ์•„๋‹Œ setItem_Name()์œผ๋กœ ์ ์šฉ๋˜์ง€ ์•Š์„๊นŒ ?
* ์ž๋ฐ” ๊ฐ์ฒด๋Š” ์นด๋ฉœ ํ‘œ๊ธฐ๋ฒ• ์‚ฌ์šฉํ•˜์ง€๋งŒ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ๋Š” ์ฃผ๋กœ ์–ธ๋”์Šค์ฝ”์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์Šค๋„ค์ดํฌ ํ‘œ๊ธฐ๋ฒ•์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
* ์ด ๋ถ€๋ถ„์„ ๊ด€๋ก€๋กœ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋‹ค๋ณด๋‹ˆ BeanPropertyRowMapper๋Š” ์–ธ๋”์Šค์ฝ”์–ด ํ‘œ๊ธฐ๋ฒ•์„ ์นด๋ฉœ๋กœ ์ž๋™์œผ๋กœ ๋ณ€ํ™˜ํ•ด ์ค๋‹ˆ๋‹ค!

SimpleJdbcInsert

insert์— ํ•œํ•ด์„œ jdbcTemplate์€ insert SQL์„ ์ง์ ‘ ์ž‘์„ฑํ•˜์ง€ ์•Š์•„๋„ ๋˜๋„๋ก SimpleJdbcInsert๋ผ๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

 

SimpleJdbcInsert๋Š” dataSource๋ฅผ ์ฃผ์ž…๋ฐ›๊ณ , Table ์ด๋ฆ„์„ ์ง€์ •ํ•˜๊ณ  key๋ฅผ ์ƒ์„ฑํ•˜๋Š” PK ์ปฌ๋Ÿผ๋ช…์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

์ถ”๊ฐ€์ ์œผ๋กœ INSERT SQL์— ์‚ฌ์šฉํ•  ํŠน์ • column์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ํŠน์ • ๊ฐ’๋งŒ ์ €์žฅํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋Š” ์˜ต์…˜์ž…๋‹ˆ๋‹ค. ์ƒ๋žต ๊ฐ€๋Šฅ.

    private final NamedParameterJdbcTemplate template;
    private final SimpleJdbcInsert jdbcInsert;

    public JdbcTemplateItemRepositoryV3(DataSource dataSource)
    {
        this.template = new NamedParameterJdbcTemplate(dataSource);
        this.jdbcInsert = new SimpleJdbcInsert(dataSource)
                .withTableName("item")
                .usingGeneratedKeyColumns("id");
//                .usingGeneratedKeyColumns("item_name","price","quantity"); // ์ƒ๋žต ๊ฐ€๋Šฅ
    }

jdbcInsert.executeAndReturnkey(param)์„ ์‚ฌ์šฉํ•ด์„œ INSERT SQL์„ ์‹คํ–‰ํ•˜๊ณ , ์ƒ์„ฑ๋œ ํ‚ค ๊ฐ’๋„ ๋งค์šฐ ํŽธ๋ฆฌํ•˜๊ฒŒ ์กฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@Override
public Item save(Item item) {
    BeanPropertySqlParameterSource param = new BeanPropertySqlParameterSource(item);
    Number key = jdbcInsert.executeAndReturnKey(param);
    item.setId(key.longValue());
    return item;
}

jdbcTemplate ๊ธฐ๋Šฅ ์ •๋ฆฌ

๊ธฐ๋Šฅ 

  • jdbctemplate : ์ˆœ์„œ ๊ธฐ๋ฐ˜ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ ์ง€์›
  • NamedParameterJdbcTemplate : ์ด๋ฆ„ ๊ธฐ๋ฐ˜ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ ์ง€์›
    • BeanPropertySqlParameterSource : ์ž๋ฐ”๋นˆ ํ”„๋กœํผํ‹ฐ ๊ทœ์•ฝ์„ ํ†ตํ•ด ์ž๋™์œผ๋กœ Type์— ๋Œ€ํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ์ฒด ์ƒ์„ฑ
    • MapSqlParameterSource : Map๊ณผ ์œ ์‚ฌ. ๋ฉ”์†Œ๋“œ ์ฒด์ธ์„ ํ†ตํ•ด ์—ฌ๋Ÿฌ ํŒŒ๋ผ๋ฏธํ„ฐ ๋“ฑ๋ก ๊ฐ€๋Šฅ 
  • SimpleJdbcInsert : insert ์ฟผ๋ฆฌ ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

๋ฉ”์†Œ๋“œ

  • ๋ณ€๊ฒฝ ( insert, update, delete ) : update() 
  • ์กฐํšŒ ( select ) : query(), queryForObejct()
  • ๊ธฐํƒ€ ( DDL ) : execute() 

 

 

<์ฐธ๊ณ ์ž๋ฃŒ>

 

Data Access

The Data Access Object (DAO) support in Spring is aimed at making it easy to work with data access technologies (such as JDBC, Hibernate, or JPA) in a consistent way. This lets you switch between the aforementioned persistence technologies fairly easily, a

docs.spring.io

 

 

๋ธ”๋กœ๊ทธ์˜ ์ •๋ณด

Study Repository

rlaehddnd0422

ํ™œ๋™ํ•˜๊ธฐ