Spring JDBC

raccoonback·2020년 7월 8일
2

boost course

목록 보기
8/10
post-thumbnail

Spring JDBC 란?

Spring JDBC는 JDBC의 모든 저수준 처리를 스프링 프레임워크에 위임하므로써, Connection 연결 객체 생성 및 종료, Statement 준비/실행 및 종료, ResultSet 처리 및 종료, 예외 처리, 트랙잭션 등의 반복되는 처리를 개발자가 직접하지 않고 Database에 대한 작업을 수행할 수있다.

아래는 기존에 Connection 연결 객체 생성 및 종료하는 예제이다.

    Connection connection = null;
    try {
        connection = dataSource.getConnection();
        if(connection != null) {
            System.out.println("DB 연결 성공!");
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if(connection != null) {
            try {
                connection.close();
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    }

이러한 반복되는 작업을 스프링 프레임워크에 위임하는 것이다.

Spring JDBC 패키지

org.springframe.jdbc.core

SQL Query 수행하기 위해 필요한 저수준 작업을 내부적으로 처리해주고 보다 추상적인 기능을 제공하는JdbcTemplate, SimpleJdbcInsert, NamedParameterJdbcTemplate 객체와 Helper 객체(RowMapper) 등을 포함한다.

따라서, JdbcTemplate 등의 객체를 이용하면 Connection 연결/종료와 같은 세부적인 작업을 직접 처리하지 않아도 된다.

또한, JDBC에서 발생하는 에러는 Runtime Exception이다. 따라서, 이를 일반 예외(Exception)로 감싸 처리해주어야 하는데 Spring JDBC는 이를 내부적으로 커스텀한 일반 예외로 변환해 전파해준다.

org.springframework.jdbc.datasource

트랜잭션 매니저 및 다양한 Datasource 구현을 제공한다.

org.springframework.jdbc.object

RDBMS queries, updates, and stored procedures 기능을 Thread-Safe하고 재사용 가능한 객체로 표현하ㄱ

org.springframework.jdbc.support

jdbc.core, jdbc.object에서 제공하는 기능을 SQLException 등으로 지원한다.

JdbcTemplate

Spring JDBC는 JdbcTemplate 객체를 상속한 보다 구체적인 목적의 기능을 가진 객체를 제공한다.

NamedParameterJdbcTemplate

JdbcTemplate에서 JDBC Statement 인자를 ?로 사용하는 대신에 :파리미터 같이 구체적인 이름 기반의 파라미터를 사용한다.

파라미터를 지정할 때에는 MapSqlParameterSource, BeanPropertySqlParameterSource 객체 등을 이용한다.

public class Role {
    private int roleId;
    private String description;

    public int getRoleId() {
        return roleId;
    }

    public void setRoleId(int roleId) {
        this.roleId = roleId;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @Override
    public String toString() {
        return "Role{" +
                "roleId=" + roleId +
                ", description='" + description + '\'' +
                '}';
    }
}
@Repository
public class RoleDao {
    public static final String SELECT_ALL = "SELECT role_id, description FROM Role order by role_id";

    private NamedParameterJdbcTemplate jdbc;
    
    // DB 테이블에서 로드한 Row 데이터를 대상으로 
    // Role Bean의 Setter 메서드에 맞춰 매핑한 객체를 반환해주는 RowMapper 객체 생성
    private RowMapper<Role> rowMapper = BeanPropertyRowMapper.newInstance(Role.class);

    public RoleDao(DataSource dataSource) {
        this.jdbc = new NamedParameterJdbcTemplate(dataSource);
    }

    public List<Role> selectAll() {
        return jdbc.query(SELECT_ALL, Collections.emptyMap(), rowMapper);
    }
}
@Configuration
@EnableTransactionManagement
public class DBConfig {
    private String driverClassName = "com.mysql.jdbc.Driver";
    private String url = "jdbc:mysql://localhost:3306/testDB?useUnicode=true&characterEncoding=utf8";

    private String username = "test";
    private String password = "test!@#";

    @Bean
    public DataSource dataSource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }
}
@Configuration
@ComponentScan(basePackages = {"kr.or.something"})
@Import({DBConfig.class})   // 외부 Configuration Class Import
public class ApplicationConfig { }
public class NamedParameterJdbcTemplateTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationConfig.class);
        RoleDao roleDao = applicationContext.getBean(RoleDao.class);
        
        List<Role> roles = roleDao.selectAll();
        for(Role role : roles) {
            System.out.println(role);
        }
    }
}

SimpleJdbcInsert

특정 테이블에 쉽게 Insert 기능을 제공하는 객체이다.

public class RoleDao {
    private SimpleJdbcInsert simpleJdbcInsert;
    private RowMapper<Role> rowMapper = BeanPropertyRowMapper.newInstance(Role.class);

    public RoleDao(DataSource dataSource) {
        simpleJdbcInsert = new SimpleJdbcInsert(dataSource)
                .withTableName("Role");
    }

    public Integer insert(Role role) {
        SqlParameterSource parameterSource = new BeanPropertySqlParameterSource(role);
        return simpleJdbcInsert.execute(parameterSource);
    }
}
public class SimpleJdbcInsertTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationConfig.class);
        RoleDao roleDao = applicationContext.getBean(RoleDao.class);

        Role role = new Role();
        role.setRoleId(1000);
        role.setDescription("Hello World!!");

        Integer count = roleDao.insert(role);
        System.out.println(count + " 건 삽입됐습니다.");
    }
}

SimpleJdbcTemplate(deprecated)

JdbcTemplateNamedParameterJdbcTemplate 에서 자주 사용되는 기능을 모아놓은 객체이다.

Connection Pool

매 요청마다 새로운 Connection을 생성하는 것은 매우 많은 비용이 든다. 따라서, 이러한 Connection을 미리 만들어 놓고 재사용한다면 불필요한 네트워크 비용을 줄일 수 있다.

Connection Pool에서 커넥션 객체를 관리하는 관리자가 필요한데, 이를 Datasource 객체가 수행한다.
Datasource 객체는 DB와 연결된 Connection 객체를 Pool에서 가져오고, 이를 다시 Pool에 반납하는 작업을 수행한다.

profile
한번도 실수하지 않은 사람은, 한번도 새로운 것을 시도하지 않은 사람이다.

0개의 댓글