JdbcTemplate는 DriverManager에 드라이버를 로드하고, Connection, Statement, ResultSet 관련 작업, 자원 해제 작업을모두 담당 해주기 때문에 상당한 소스코드를 줄일 수 있게 된다.
이제 Spring JdbcTemplate의 사용법을 설정부터 차근차근 알아가보도록 하자.
※이 포스팅에서는 Oracle 데이터베이스를 사용함
1. dependency 추가
JdbcTemplate을 사용하기 위해 pom.xml에 다음과 같이 dependency를 추가해준다.
</dependencies>
...
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
</dependencies>
2. bean 추가
servlet-context.xml 에 2개의 bean을 추가로 작성한다.
"dataSource" bean : spring에서 제공하는 DriverManagerDatasource 클래스로부터 bean 객체를 생성하고, property를 설정한다.
"template" bean : spring에서 제공하는 JdbcTemplate 클래스로부터 bean 객체를 생성하고, name property에서 참조 객체로 "dataSource"를 사용하겠다고 지정한다. 바로 위에서 만든 "dataSource" bean을 참조하는 것이다.
<beans:beans ...>
...
<beans:bean name="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<beans:property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<beans:property name="url" value="jdbc:oracle:thin:@localhost:1521:xe"/>
<beans:property name="username" value="DB아이디"/>
<beans:property name="password" value="DB비밀번호"/>
</beans:bean>
<beans:bean name="template" class="org.springframework.jdbc.core.JdbcTemplate">
<beans:property name="dataSource" ref="dataSource"></beans:property>
</beans:bean>
</beans:beans>
※ DriverManagerDataSource의 driverClassName은 Class형인데, 프로퍼티 주입을 할 때 String형인 property의 value 속성을 사용하는 이유는 내부적으로 driverClassName의 수정자 메소드(setter)가 파라미터 타입을 참고로 해서 적절한 형태로 변환해주기 때문이다.
3. Connection Pool 설정
Connection Pool에 대한 개념이 생소하다면, 아래 포스팅의 3.ConnectionPool을 참고하면 도움이 될 것이다.
간단하게 말하면, 지나친 connection 객체 생성을 방지하는 용도라고 생각하면 된다.
Tomcat의 context.xml의 <Context> 컴포넌트 내에 다음과 같이 Resource를 추가해준다.
username, password에는 여러분들의 데이터베이스 아이디와 비밀번호를 작성하면 된다.
<Resource
auth="Container"
driverClassName = "oracle.jdbc.driver.OracleDriver"
url = "jdbc:oracle:thin:@localhost:1521:xe"
username = "DB아이디"
password = "DB비밀번호"
name = "jdbc/test"
type = "javax.sql.DataSource"
maxActive = "40"
maxWait = "1000"
/>
4. JdbcTemplate 주입
<beans:bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<beans:property name="dataSource" ref="dataSource"/>
</beans:bean>
<beans:bean name="dataSource" ...>
@Autowired
JdbcTemplate jdbcTemplate;
5. 사용 예시
이제 본격적으로 JdbcTemplate으로 데이터베이스에 접근해볼 것이다.
<HomeController.java>
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HomeController {
@RequestMapping("/list")
public String list(Model model) {
Command command = new ListCommand();
command.execute(model);
return "list";
}
}
<ListCommand.java>
HomeController.java의 list 메소드에서 호출된 ListCommand 클래스이다.
Command 인터페이스의 execute() 메소드를 Override 했다.
package com.example.demo;
import java.util.ArrayList;
import org.springframework.ui.Model;
public class ListCommand implements Command {
@Autowired Dao dao;
@Override
public void execute(Model model) {
ArrayList<User> users = dao.list();
model.addAttribute("users", users);
}
}
<Command.java>
execute 메소드가 있는 interface이다.
package com.example.demo;
import org.springframework.ui.Model;
public interface Command {
void execute(Model model);
}
<User.java>
DTO(Bean) 클래스이다.
package com.example.demo;
public class User {
private String id;
private String pw;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPw() {
return pw;
}
public void setPw(String pw) {
this.pw = pw;
}
}
<Dao.java>
- DriverManager에 드라이버를 로드하고, Connection, Statement, ResultSet 객체를 생성하고 자원해제하는 과정이 모두 JdbcTemplate에 맡겨져서 소스 코드가 상당히 단축되었다.
- DAO의 list 메소드에는 단 두 줄의 소스코드가 작성되었다.
- JdbcTemplate의 query() 메소드는 쿼리에 맞는 여러 레코드들을 반환하는 메소드로, 첫 번째 인자에는 쿼리문이 들어오고, 두 번째 인자에는 RowMapper 객체가 들어있다. RowMapper 객체는 여러 개의 컬럼값을 가진 레코드를 하나의 오브젝트로 전환할 때 사용되며, 특히 BeanPropertyRowMapper은 DB 테이블의 속성명과 오브젝트의 프로퍼티명이 일치할 경우 사용하면 된다.
- 여기에는 작성되지는 않았지만 queryForObject 라는 메소드도 있는데, 이는 쿼리에 맞는 하나의 레코드를 반환하는 메소드이다.
- User은 DTO이며, list 메소드는 query의 반환 레코드들을 ArrayList<User>으로 형변환 하여 return한다.
package com.example.demo;
import java.util.ArrayList;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
public class Dao {
@Autowired
JdbcTemplate jdbcTemplate;
public ArrayList<User> list(){
String query = "select * from member";
return (ArrayList<User>)jdbcTemplate.query(query,new BeanPropertyRowMapper<User>(User.class));
}
}
데이터베이스를 업데이트하는 UPDATE, DELETE, INSERT문 같은 경우에는 query메소드 대신 update메소드를 사용하게 된다. 이들은 쿼리가 실행에 따라 달라지기 때문에 쿼리 내에 변수를 설정해야 좋고, 변수가 들어갈 자리는 "?"로 표시 하면 된다.
쿼리 내에 변수를 설정하기 위해서는 update메소드의 2번째 인자에 PreparedStatementSetter 클래스 객체를 넣으면 된다.
아래 포스팅의 중간에 PrepardStatement에 대해 설명한 부분이 있다.
이제 update메소드를 사용하여 INSERT문 쿼리를 적용하는 예제를 보자. DELETE, UPDATE문도 이렇게 하면 된다.
쿼리를 설명하자면 "member" 테이블의 "ID", "PW" 필드의 필드값에 두 ? 변수를 각각 넣으라는 의미이다.
update 메소드의 2번째 parameter로 PreparedStatementSetter 클래스를 익명 클래스로 작성하였고,
PreparedStatementSetter 클래스는 setValues 메소드가 Override 되어야 한다.
setValues 메소드에서 다음과 같이 쿼리 변수에 값을 채워 넣으면 된다.
public void insertEx(final String id, final String pw){
String query = "insert into member (ID, PW) values (?,?)";
jdbcTemplate.update(query,new PreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps) throws SQLException {
ps.setString(1, id);
ps.setString(2, pw);
}
});
}
'Spring Series > Spring Framework' 카테고리의 다른 글
[Spring] Spring Security(1) - 기본 사용법 (0) | 2021.01.19 |
---|---|
[Spring] JDBC 트랜잭션 (0) | 2021.01.14 |
[Spring] 게시판 설계 준비과정 (0) | 2021.01.07 |
[Spring] Validator로 form 데이터 검증하기 (0) | 2021.01.06 |
[Spring] Controller에서 redirect하기 (0) | 2021.01.05 |
댓글