[Spring] JDBCTemplate

DANIยท2023๋…„ 12์›” 21์ผ

[Class] Spring-basic

๋ชฉ๋ก ๋ณด๊ธฐ
2/8
post-thumbnail

๐Ÿ“• JDBCTemplate ์ด๋ž€?

JdbcTemplate์€ ์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์ œ๊ณตํ•˜๋Š” JDBC(Java Database Connectivity) ๊ธฐ๋ฐ˜์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์•ก์„ธ์Šค๋ฅผ ๋‹จ์ˆœํ™”ํ•˜๊ณ  ํŽธ๋ฆฌํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ํด๋ž˜์Šค์ด๋‹ค. JDBC๋Š” ์ž๋ฐ”์—์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€์˜ ์—ฐ๊ฒฐ์„ ๊ด€๋ฆฌํ•˜๊ณ  SQL ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ํ‘œ์ค€ API์ด๋ฉฐ, JdbcTemplate์€ ์ด๋Ÿฌํ•œ JDBC ๊ธฐ๋Šฅ์„ ๋” ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์Šคํ”„๋ง์—์„œ ์ œ๊ณตํ•˜๋Š” ๋„๊ตฌ ์ค‘ ํ•˜๋‚˜์ด๋‹ค.

JdbcTemplate์„ ์‚ฌ์šฉํ•˜๋ฉด ์ผ๋ฐ˜์ ์ธ JDBC ์ฝ”๋“œ์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ˜๋ณต์ ์ด๊ณ  ์ง€๋ฃจํ•œ ์ž‘์—…๋“ค์„ ์ค„์ผ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๋ฐ ๋ฆฌ์†Œ์Šค ๊ด€๋ฆฌ ๋“ฑ์„ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•ด์ค€๋‹ค.



๐Ÿ” JDBCTemplate์˜ ์ด์ 

  • ๊ฐ„๊ฒฐํ•œ ์ฝ”๋“œ
    : JDBC ์ฝ”๋“œ๋Š” ๋ณดํ†ต ๋งŽ์€ ๋ถ€๋ถ„์ด ๋ฐ˜๋ณต๋˜๊ณ  ๋ฒˆ๊ฑฐ๋กœ์šด๋ฐ, JdbcTemplate์„ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋Ÿฌํ•œ ๋ถ€๋ถ„์„ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ„๊ฒฐํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ๋‹ค์–‘ํ•œ ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

  • ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์ž๋™ํ™”
    : JdbcTemplate์€ JDBC ์—ฐ์‚ฐ ์ค‘ ๋ฐœ์ƒํ•˜๋Š” ์ผ๋ฐ˜์ ์ธ ์˜ˆ์™ธ๋“ค์„ ์ฒ˜๋ฆฌํ•ด์ฃผ๋Š”๋ฐ, ์ด๋ฅผ ํ†ตํ•ด ๋ช…์‹œ์ ์ธ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ฝœ๋ฐฑ ํŒจํ„ด ํ™œ์šฉ
    : JdbcTemplate์€ JDBC ์—ฐ์‚ฐ์˜ ์ผ๋ถ€ ๋˜๋Š” ์ „์ฒด๋ฅผ ์ฝœ๋ฐฑ ํŒจํ„ด์„ ํ†ตํ•ด ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž๋Š” ํŠน์ • ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๋กœ์ง์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(RowMapper์™€ PreparedStatementCallback).

  • ํŽธ๋ฆฌํ•œ ResultSet ์ฒ˜๋ฆฌ
    : JdbcTemplate์€ RowMapper ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ตํ•ด ResultSet์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ž๋ฐ” ๊ฐ์ฒด๋กœ ๋งคํ•‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ฐ˜๋ณต์ ์ธ ResultSet ์ฒ˜๋ฆฌ๋ฅผ ํŽธ๋ฆฌํ•˜๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

  • ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ
    : JdbcTemplate์€ ์Šคํ”„๋ง์˜ ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ €์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์–ด์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํŠธ๋žœ์žญ์…˜์„ ์‰ฝ๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.



๐Ÿ“ 1. spring-jdbc

spring-jdbc๋Š” Spring Framework์—์„œ ์ œ๊ณตํ•˜๋Š” JDBC(Java Database Connectivity) ์ง€์›์„ ๋‹ด๋‹นํ•˜๋Š” ๋ชจ๋“ˆ ์ค‘ ํ•˜๋‚˜๋กœ์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€์˜ ์—ฐ๊ฒฐ์„ ๊ด€๋ฆฌํ•˜๊ณ  JDBC ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐ ๋„์›€์„ ์ฃผ๋Š” ์—ฌ๋Ÿฌ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค์™€ API๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ๋‹ค.

JDBC API๋ฅผ ๊ฐœ์„ ํ•˜๋ฉด์„œ ์ปค๋„ฅ์…˜ ํ’€์„ ์ œ๊ณตํ•˜๋Š” ํ™•์žฅ๋œ API

  • ์˜์กด์„ฑ ์ถ”๊ฐ€ : "org.springframework:spring-jdbc:$spring_version"

Spring Framework์—์„œ spring-jdbc ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•  ๋•Œ, ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฐฉ์‹์œผ๋กœ ์ปค๋„ฅ์…˜ ํ’€์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ Spring์€ ์™ธ๋ถ€ ์ปค๋„ฅ์…˜ ํ’€์„ ์‚ฌ์šฉํ•˜๋„๋ก ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ Tomcat์˜ DataSource๊ฐ€ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š”๋ฐ, ์ด๋Š” Apache Tomcat์ด ๋‚ด์žฅํ•˜๊ณ  ์žˆ๋Š” ์ปค๋„ฅ์…˜ ํ’€ ๊ตฌํ˜„์ฒด ์ค‘ ํ•˜๋‚˜์ด๋‹ค.


  1. ์Šคํ”„๋ง jdbc๋Š” ์ปค๋„ฅ์…˜ ํ’€์„ ์ง€์›ํ•˜๋Š” API์ด๋‹ค
  2. API๋Š” ๊ตฌํ˜„์ฒด๊ฐ€ ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•˜๋ฉฐ, ์ด๋•Œ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ๊ตฌํ˜„์ฒด๋Š” tomcat-jdbc์˜ DataSource์ด๋‹ค.


๐Ÿ“ 2. tomcat-jdbc / HikariCP(๋งŽ์ด ์‚ฌ์šฉํ•จ)

์ฆ‰, spring-jdbc๋Š” ์ปค๋„ฅ์…˜ ํ’€์„ ์ง€์›ํ•˜๋Š” API์ด๊ณ , tomcat-jdbc์˜ DataSource๋Š” ์ปค๋„ฅ์…˜ ํ’€์˜ ๊ตฌํ˜„์ฒด ์ด๋‹ค.

  • DriverManger -> ์ปค๋„ฅ์…˜ ํ’€ ์—†์Œ : ์ผ๋ฐ˜์ ์ธ ์ ‘์†
  • ์˜์กด์„ฑ ์ถ”๊ฐ€ : implementation 'org.apache.tomcat:tomcat-jdbc:10.1.16'

Tomcat์˜ DataSource๋Š” ์ปค๋„ฅ์…˜์„ ํ’€์— ๋ฐ˜ํ™˜ํ•˜์—ฌ ์žฌ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์ปค๋„ฅ์…˜์„ ๋‹ซ์„ ํ•„์š”๊ฐ€ ์—†๋‹ค.

Tomcat์˜ DataSource๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ปค๋„ฅ์…˜ ๊ด€๋ฆฌ์— ๋Œ€ํ•œ ๋ถ€๋‹ด์ด ๊ฐ์†Œํ•˜๊ณ , ์ปค๋„ฅ์…˜ ํ’€๋ง์„ ํ†ตํ•ด ์„ฑ๋Šฅ์ด ํ–ฅ์ƒ๋œ๋‹ค. ๊ฐœ๋ฐœ์ž๋Š” ์ปค๋„ฅ์…˜์„ ์–ป์€ ํ›„์— ํ•„์š”ํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ณ , ์ปค๋„ฅ์…˜์„ ๋‹ซ์•„์ฃผ๋Š” ๋Œ€์‹  ๋ฐ˜ํ™˜๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.


โœจ ์ด ๋•Œ, ์ปค๋„ฅ์…˜ ํ’€์€ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด ๋†“์€ ๊ฐ์ฒด๋ฅผ ๋ฐ›์•„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ์—ฐ๊ฒฐ๋œ ๊ฐ์ฒด๊ฐ€ ์œ ํœด์ƒํƒœ์ธ์ง€ ์ฒดํฌํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค. ์˜ค๋žœ์‹œ๊ฐ„ ์—ฐ๊ฒฐ์ด ๋˜์–ด์žˆ์ง€ ์•Š์œผ๋ฉด DB์™€์˜ ์—ฐ๊ฒฐ์ด ๋Š๊ธฐ๊ณ  ์—ฐ๊ฒฐ์ด ๋Š๊ธฐ๊ฒŒ ๋˜๋ฉด ์˜ค๋ฅ˜๊ฐ€ ์ƒ๊ธฐ๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ DB์™€ ์—ฐ๊ฒฐ๋œ ์ƒํƒœ์ธ์ง€ ์ฃผ๊ธฐ์ ์œผ๋กœ ์ฒดํฌํ•ด์•ผ ํ•œ๋‹ค.โœจ

tomcat-jdbc : ์ปค๋„ฅ์…˜ ํ’€์„ ์ง€์›ํ•˜๋Š” ์—ฐ๊ฒฐ ๊ฐ์ฒด -> ์ž์›์„ ์†Œ๋น„ํ•จ -> ์ž์› ํ•ด์ œํ•ด์ค˜์•ผํ•จ



๐Ÿ’พ DBConfig ์„ค์ • ํŒŒ์ผ

@Configuration
public class DBConfig {

    @Bean(destroyMethod = "close")
    public DataSource dataSource(){
        DataSource dataSource = new DataSource();
        dataSource.setDriverClassName("oracle.jdbc.OracleDriver");
        dataSource.setUrl("jdbc:oracle:thin:@localhost:1521:xe");
        dataSource.setUsername("spring6");
        dataSource.setPassword("aA123456");

        dataSource.setInitialSize(2); // ์ปค๋„ฅ์…˜ ํ’€์„ ์ดˆ๊ธฐํ™” ํ•  ๋•Œ ์ƒ์„ฑํ•  ๊ฐฏ์ˆ˜ ๋งŽ์œผ๋ฉด ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆผ
        dataSource.setTestWhileIdle(true); // db์™€์˜ ์—ฐ๊ฒฐ์ด ๋Š์–ด์กŒ๋Š” ์ง€ ํ™•์ธ
        dataSource.setTimeBetweenEvictionRunsMillis(3000); // ์œ ํšจ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•  ์ตœ์ดˆ ์‹œ๊ฐ„
        dataSource.setMinEvictableIdleTimeMillis(30*1000); // ์œ ํšจ ์ปค๋„ฅ์…˜์„ ๊ฒ€์‚ฌํ•  ์ฃผ๊ธฐ ์‹œ๊ฐ„
        return dataSource;
    }

    @Bean
    public JdbcTemplate jdbcTemplate(){
        return new JdbcTemplate(dataSource());
    }
}


๐Ÿ“ 3. JdbcTemplate์„ ์ด์šฉํ•œ ์ฟผ๋ฆฌ์‹คํ–‰

์ž์›ํ•ด์ œ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š๊ณ  ์ปดํŒŒ์ผ์˜ˆ์™ธ๊ฐ€ ์•„๋‹Œ ๋Ÿฐํƒ€์ž„์˜ˆ์™ธ๋กœ ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์— SQLException๋“ฑ try catch๋กœ ์žก์ง€ ์•Š์•„๋„ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋•Œ๋•Œ๋กœ try catch๊ฐ€ ํ•„์š”ํ•˜๊ธฐ๋„ ํ•จ

์ž๋™ ๋งคํ•‘์ด ๋จ ํŠน์ • ๋ฐ์ดํ„ฐ ๊ฐ์ฒด๋กœ ๋ฐ˜ํ™˜ํ•ด์ฃผ๋Š” ๋กœ์ง์ด ์žˆ๋‹ค.

๊ฐ ์—ฐ๋™ ๊ธฐ์ˆ ์— ๋”ฐ๋ผ ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ์™ธ๋ฅผ ์Šคํ”„๋ง์ด ์ œ๊ณตํ•˜๋Š” ์˜ˆ์™ธ๋กœ ๋ณ€ํ™˜ํ•จ์œผ๋กœ์จ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌํ˜„ ๊ธฐ์ˆ ์— ์ƒ๊ด€์—†์ด ๋™์ผํ•œ ์ฝ”๋“œ๋กœ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

  • SQLException, HibernateException, PersistenceException -> DataAccessException(RuntimeException)

๐Ÿ” JDBC API


  • ์กฐํšŒ(SELECT)
    ResultSet executeQuery(..)
  • ๋ณ€๊ฒฝ(INSERT, UPDATE, DELETE)
    int executeUpdate(..) : ๋ฐ˜์˜๋œ ๋ ˆ์ฝ”๋“œ ๊ฐœ์ˆ˜ ๋ฐ˜ํ™˜

๐Ÿ’พ query API : ๋ชฉ๋ก ๋ฐ์ดํ„ฐ ์กฐํšŒ

<T> List<T> query(String sql, RowMapper<T> rowMapper)
/* Execute a query given static SQL, mapping each row to a result object via a RowMapper. */
<T> List<T> query(String sql, RowMapper<T> rowMapper, Object... args)
/* Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, mapping each row to a result object via a RowMapper. */
  • RowMapper<T> : ๋ณ€ํ™˜, ๊ฒ€์ƒ‰ db์—์„œ ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•ด์คŒ
  • ... : ๊ฐ€๋ณ€์ 

new RowMapper<Member>() {
	@Override
    public Member mapRow(ResultSet rs, int rowNum) throws SQLException {
    	return null;
    }
});

RowMapper๋Š” JDBC ๊ฒฐ๊ณผ์…‹์—์„œ ๊ฐ ํ–‰(row)์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์–ด๋–ป๊ฒŒ ์ถ”์ถœํ• ์ง€ ์ •์˜ํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋กœ์„œ ๊ตฌํ˜„์„ ํ†ตํ•ด ResultSet์—์„œ ์ฝ์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ž๋ฐ” ๊ฐ์ฒด์˜ setter๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ๋งคํ•‘ํ•  ์ˆ˜ ์žˆ๋‹ค.
ResultSet์€ ์ปค์„œ์˜ ์œ„์น˜๋ฅผ ์˜๋ฏธํ•˜๊ธฐ ๋•Œ๋ฌธ์— next๋กœ ๋‹ค์Œ ๊ฐ’์„ ๋ถˆ๋Ÿฌ์™€์•ผ ํ•˜๋Š”๋ฐ JDBCTemplate์˜ query๋ฉ”์„œ๋“œ๋Š” mapRow๋ผ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ตํ•ด ์‰ฝ๊ฒŒ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.


๐Ÿ”ด update - selectTest

	@Test
    @DisplayName("์กฐํšŒํ…Œ์ŠคํŠธ")
    void selectTest(){
        String sql = "select * from member";
        List<Member> memberList = jdbcTemplate.query(sql, this::mapper);
        memberList.stream().forEach(System.out::println);
    }
    
    private Member mapper(ResultSet rs, int i) throws SQLException{
        return Member.builder()
                .userId(rs.getString("USER_ID"))
                .userPw(rs.getString("USER_PW"))
                .userName(rs.getString("USER_NAME"))
                .userNo(rs.getLong("USER_NO"))
                .email(rs.getString("EMAIL"))
                .build();
    }

๐Ÿ’พ update API : ์ถ”๊ฐ€, ์ˆ˜์ •, ์‚ญ์ œ

int update(String sql)
/* Issue a single SQL update operation (such as an insert, update or delete statement). */
int update(String sql, Object... args)
/* Issue a single SQL update operation (such as an insert, update or delete statement) via a prepared statement, binding the given arguments. */

๐Ÿ”ด update - insertTest

@ExtendWith(SpringExtension.class)
// ํ…Œ์ŠคํŠธํ™˜๊ฒฝ์—์„œ์˜ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋กœ ์‚ฌ์šฉํ•  ํด๋ž˜์Šค
@ContextConfiguration(classes = AppConfig.class)
class DBConfigTest {

    @Autowired
    private DataSource dataSource;

    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    @Test
    void insertTest(){
        // DataAccessException -> RuntimeException = ์˜ˆ์™ธ์ฒ˜๋ฆฌ x
        String sql = "insert into member (user_no, user_id, user_name, user_pw, email)" +
                "values (seq_member.nextval, ?, ?, ?, ?)";
        int update = jdbcTemplate.update(sql, "user01", "hong01", "123456", "e@e");
        System.out.println(update); // 1
    }
 }

๐Ÿ” SQL Log ํ™•์ธํ•˜๊ธฐ

  • API : slf4j-api
  • ๊ตฌํ˜„์ฒด : logback-classic
  • ์ •๋ณด์˜ ์–‘์— ๋”ฐ๋ผ ๋กœ๊ทธ ๋ ˆ๋ฒจ์ด ์žˆ์Œ / ์•„๋ž˜๋กœ ๊ฐˆ์ˆ˜๋ก ์–‘์ด ๋งŽ์•„์ง
    - FATAL
    - ERROR
    - WARN : ๊ธฐ๋Šฅ์— ๋ฌธ์ œ๋Š” ์—†์ง€๋งŒ, ํ–ฅํ›„ ๋ฌธ์ œ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Œ
    (์ •๋ณด์„ฑ ๋กœ๊ทธ)
    - INFO
    - DEBUG
    - TRACE

xml properties๋กœ ๋กœ๊ทธ๋ ˆ๋ฒจ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Œ -> ํŒจํ‚ค์ง€๋Š” resource : ์ •์  ์ž์›

๐Ÿ’พ logback.xml

<?xml version="1.0" encoding="UTF-8" ?>

<configuration>
    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d %5p %c{2} - %m%n</pattern>
        </encoder>
    </appender>
    <root level="INFO">
        <appender-ref ref="stdout" />
    </root>

    <logger name="org.springframework.jdbc" level="TRACE" />
</configuration>
  • ConsoleAppender : ์ฝ˜์†”ํ™”๋ฉด์— ๋กœ๊ทธ ์ถœ๋ ฅ / html๋“ฑ ํŒŒ์ผ๋กœ ์ถœ๋ ฅํ•˜๋Š” ๊ฒฝ์šฐ๋„ ์žˆ์Œ
  • %d %5p %c{2} - %m%n : %d(๋‚ ์งœ, ์‹œ๊ฐ„) / %5p(5์ž ๋‚ด์—์„œ ๋กœ๊ทธ ๋ ˆ๋ฒจ ์ถœ๋ ฅ) / %c{2}(ํŒจํ‚ค์ง€๋ฅผ ํ•œ๊ธ€์ž๋กœ ์š”์•ฝ + ํด๋ž˜์Šค๋ช…) / %m(์ถœ๋ ฅ ๋ฉ”์„ธ์ง€)
  • INFO : ๊ธฐ๋ณธ ๋ ˆ๋ฒจ์„ ์ธํฌ๋กœ ์„ค์ •ํ•˜์—ฌ ์ธํฌ ์ด์ƒ ๋ชจ๋“  ๋ ˆ๋ฒจ ์ถœ๋ ฅ
  • <logger name="org.springframework.jdbc" level="TRACE" /> : ํŠน์ • ํŒจํ‚ค์ง€๋Š” ๋””๋ฒ„๊ทธ๋ ˆ๋ฒจ


๐Ÿ“ 4. PreparedStatementCreator๋ฅผ ์ด์šฉํ•œ ์ฟผ๋ฆฌ ์‹คํ–‰

๐Ÿ”ด PreparedStatementCreator - KeyHolder(์ž๋™์ƒ์„ฑ ํ‚ค๊ฐ’) ์‚ฌ์šฉ

@ExtendWith(SpringExtension.class)
// ํ…Œ์ŠคํŠธํ™˜๊ฒฝ์—์„œ์˜ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋กœ ์‚ฌ์šฉํ•  ํด๋ž˜์Šค
@ContextConfiguration(classes = AppConfig.class)
class DBConfigTest {

    @Autowired
    private DataSource dataSource;

    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    @Test
    @DisplayName("insertํ›„ ์‹œํ€€์Šค ๋ฒˆํ˜ธ ์ถ”์ถœํ•˜๊ธฐ")
    void insertTest2() {
            KeyHolder keyHolder = new GeneratedKeyHolder();
            int affectedRows = jdbcTemplate.update(con -> {
                        String sql = "INSERT INTO MEMBER (USER_NO, USER_ID, USER_PW, USER_NAME, EMAIL) \n" +
                                "VALUES (SEQ_MEMBER.nextval, ?, ?, ?, ?)";
                        PreparedStatement preparedStatement = con.prepareStatement(sql, new String[]{"USER_NO"});
                        preparedStatement.setString(1, "USER201");
                        preparedStatement.setString(2, "123456");
                        preparedStatement.setString(3, "์‚ฌ์šฉ์ž201");
                        preparedStatement.setString(4, "USER199@test.org");
                        return preparedStatement;
                    }
                    , keyHolder);
//        keyHolder.getKey();  ๋ฐ˜ํ™˜ ํƒ€์ž…์ด NUMBER์ž„
            Long key = keyHolder.getKey().longValue();
            System.out.println(key);
      }
    
 }


๐Ÿ“ 5. queryForObject() : ๋‹จ์ผ ๋ฐ์ดํ„ฐ ์กฐํšŒ, ํ†ต๊ณ„ํ˜• ๋ฐ์ดํ„ฐ

๐Ÿ”ด queryForObject() : ์˜ˆ์™ธ์— ๋ฏผ๊ฐ (DataAccessException ์˜ˆ์™ธ)

@ExtendWith(SpringExtension.class)
// ํ…Œ์ŠคํŠธํ™˜๊ฒฝ์—์„œ์˜ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋กœ ์‚ฌ์šฉํ•  ํด๋ž˜์Šค
@ContextConfiguration(classes = AppConfig.class)
class DBConfigTest {

    @Autowired
    private DataSource dataSource;

    @Autowired
    private JdbcTemplate jdbcTemplate;
    
	@Test
    @DisplayName("1๊ฑด ์กฐํšŒ")
    void selectTest2(){
        String user_id = "USER201";
        String sql = "select * from member where user_id = ?";
        try {
            Member member = jdbcTemplate.queryForObject(sql, this::mapper, user_id); // ์˜ˆ์™ธ์— ๋ฏผ๊ฐํ•˜๋‹ค.
            System.out.println(member);
        }catch (DataAccessException e){
            System.out.println("์กฐํšŒ๋œ ๋ฐ์ดํ„ฐ ์—†์Œ");
        }
    }
    
    @Test
    @DisplayName("๋ฉค๋ฒ„์ˆ˜ ์กฐํšŒ")
    void selectTest3(){
        String sql="select count(*) from member";
        Long l = jdbcTemplate.queryForObject(sql, long.class);
        System.out.println(l);
    }
 }


๐Ÿ“ 6. @Transactional

SQL์˜ ์‹คํ–‰ ๋‹จ์œ„๋กœ commit(DB์˜๊ตฌ๋ฐ˜์˜)์ „ ๊นŒ์ง€๊ฐ€ ํ•˜๋‚˜์˜ ํŠธ๋žœ์žญ์…˜์ด๋‹ค.
ํŠธ๋žœ์žญ์…˜์„ ์ˆ˜๋™์œผ๋กœ ๊ด€๋ฆฌํ•ด์ค˜์•ผ ํ•  ๋•Œ(์—ฐ์†๋œ ์ปค๋ฆฌ๋Š” ์ˆ˜๋™์œผ๋กœ ๊ด€๋ฆฌํ•ด์•ผํ•จ) ์‚ฌ์šฉ

  • ๊ธฐ๋ณธ๊ฐ’ : autocommit(true) : 1๊ฐœ SQL ์‹คํ–‰์‹œ ์ž๋™ COMMIT- ๊ธฐ๋ณธ๊ฐ’ : autocommit(true) : 1๊ฐœ SQL ์‹คํ–‰์‹œ ์ž๋™ COMMIT

๐Ÿ’พ DBConfig.class์— ๋นˆ ์ถ”๊ฐ€

    /**
     * PlatformTransactionManager : ์ธํ„ฐํŽ˜์ด์Šค
     * DataSourceTransactionManager : ๊ตฌํ˜„์ฒด
     */
    @Bean
    public PlatformTransactionManager transactionManager(){
        DataSourceTransactionManager tm = new DataSourceTransactionManager(dataSource());
        return tm;
    }

ํŠธ๋žœ์žญ์…˜ ๊ด€๋ จ๋œ ๋ถ€๋ถ„์„ ๋นˆ์œผ๋กœ ์ถ”๊ฐ€ํ•œ๋‹ค. (์Šคํ”„๋ง๋ถ€ํŠธ์—์„  ์ž๋™)

๐Ÿ’พ @Transactional ์• ๋„ˆํ…Œ์ด์…˜(ํŠธ๋žœ์žญ์…˜ AOP)

conn.setAutocommit(false); // ๊ณตํ†ต ๊ธฐ๋Šฅ 

// ํ•ต์‹ฌ ๊ธฐ๋Šฅ
SQL1 
SQL2
SQL3
...

conn.commit(); // ๊ณตํ†ต ๊ธฐ๋Šฅ

PlatformTransactionManager๊ฐ€ ์œ„์˜ ๋กœ์ง์„ ํ”„๋ก์‹œ๋กœ ๊ตฌํ˜„ํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— @Transactional ์• ๋„ˆํ…Œ์ด์…˜์ด ๋ถ™์€ ํด๋ž˜์Šค๋‚˜ ๋ฉ”์„œ๋“œ๋Š” ์œ„ ๋กœ์ง์ด ์ ์šฉ๋œ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€