SimpleDriverDataSource : 실전에선 절대 사용하지 않을것. 테스트용으로만!
SingleConnectionDataSource : 하나의 물리적인 DB커넥션만 만들어놓고 이를 계속 사용함. 따라서 멀티스레스환경에서 사용하면 하나의 커넥션을 공유하므로 위험.
과거 : Apache Commons DBCP, C3P0
현재 : HikariCP (히카리CP) → 사실상 Spring Boot 기본
JDBC : 자바의 데이터 액세스 기술의 기본이 되는 로우레벨의 API이다.
템플릿/콜백 패턴 덕분에 DataSource가 바뀌어도 그대로 이용 가능!
SimpleJdbcTemplate : 실행,조회,배치 세가지 작업으로 구분된다.
실행 : insert, update등
조회 : select
batch : 대량의 쿼리를 캐싱해서 한번에 보냄. (네트워크 횟수 줄어듦)
SimpleJdbcTemplate는 치환자인 "?" 뿐만 아니라 이름 치환자도 지원한다.
INSERT INTO MEMBER(ID, NAME, POINT) VALUES(1,'Spring', 2.3);
INSERT INTO MEMBER(ID, NAME, POINT) VALUES(?, ?, ?);
INSERT INTO MEMBER(ID, NAME, POINT) VALUES(:id, :name, :point);
Map<String, Object> map = new HashMap<String, Object>();
map.put("id", 1);
map.put("name", "spring");
map.put("point", 3.5);
BeanPropertySqlParameterSource : 도메인 오브젝트나 DTO가 빈으로 등록 되어있으면 맵 대신 프로퍼티 이름과 매치해서 파라미터 값 넣어줌.
Member member = new Member(1, "Spring", 3.5);
BeanPropertySqlParameterSource params = new BeanPropertySqlParameterSource(member);
String name = SimpleJdbcTemplate.queryForObject("select name from member where id = ?", String.class, id);
- 검색된 row가 없으면 EmptyResultDataAccessException 반환됨.
Member m = SimpleJdbcTemplate.queryForObject("select * from member where id = ?", new BeanPropertyRowMapper<Member>(member.class), id;
- RowMapper를 직접 구현하는 대신 BeanPropertyRowMapper<T> 사용하는게 더 편함.
- 검색된 결과가 없거나 여러개면 예외발생
List<Member> members = simpleJdbcTemplate.query("select * from member where point > ?", new BeanPropertyRowMapper<Member>(Member.class), point);
- 결과가 0개여도 예외발생하지 않음!
Map<String, Object> map = simpleJdbcTemplate.queryForMap("select *from member where id = ?", id);
- queryForObject() 와 마찬가지로 SQL 실행 결과는 하나의 row를 돌려줘야함. 아니면 예외터짐
update()로 실행하는 SQL들을 배치 모드로 실행하게 해준다.
내부적으로 JDBC statment의 addBatch()와 executeBatch() 메소드를 이용하면 여러개의 SQL를 한번에 처리한다. 많은 SQL을 실행해야 하는 경우 배치 방식을 사용하면 DB 호출을 최소화 할 수 있기 때문에 성능 향상 가능!
int[] batchUpdate(String sql, Map<String, ?>[] batchValues)
이름 치환자를 가진 SQL에 파라미터 정보가 담긴 맵의 배열을 이용한다.
배열의 개수만큼 SQL을 실행해준다.
리턴값은 각 SQL을 실행 했을때 영향받은 로우의 개수를 담은 배열이다.
int[] batchUpdate(String sql, SqlParameterSource[] batchArgs)
맵 대신 SqlParameterSource 타입 오브젝트 배열로 파라미터를 넣을 수 있ㄷ음.
dao.simpleJdbcTemplate.batchUpdate("update member set name = :name where id = :id", new SqlParameterSource[]{
new MapSqlParameterSource().addValue("id",1).addValue("name","Spring3"),
new BeanPropertySqlParameter(new Member(2, "Book3"))
});
DB에 생성해둔 저장 프로시저 또는 저장 펑션을 호출할 때 사용한다.
SimpleJdbcCall은 dataSource를 이용해 생성한다.
멀티스레드 환경에서 안전하게 작동하므로 공유해서 사용해도 된다.
기본적으로 실행할 저장 프로시저나 저장 펑션 중의 하나로 초기화 해야함.
SimpleJdbcCallOperations withProcedureName(String procedureName)
-> 실행할 프로시저 이름을 지정한다.
SimpleJdbcCallOperations withFunctionName(String functionName)
-> 실행할 펑션의 이름을 지정한다.
SimpleJdbcCallOperations returningResultSet(String parameterName, RowMapper<?> rowMapper);
-> 프로시저가 ResultSet을 도려주는 경우에는 이를 RowMapper를 이용해 매핑해준다.
T executeFunction(Class returnType, Object... args);
-> 저장펑션을 실행해주는 메소드다. 리턴 값을 타입과 SQL파라미터를 전달해주면 된다.
create function find_name(in_id INT)
returns varchar(255)
begin
declare out_name varchar(255);
select name
into out_name
from member
where id = in_id;
return out_name;
end
SimpleJdbcCall call = new SimpleJdbcCall(dataSource).withFunctionName("find_name");
String ret = call.executeFunction(String.class, id);
스프링 JDBC를 이용해 DAO클래스를 설계하는 방법을 알아보자.
DataSource는 DI를 통해 주입받고, 스프링 JDBC오브젝트는 코드를 이용해 직접 생성하거나 초기화해서 DAO의 인스턴스 변수에 저장해두고 사용하자.
public class MemberDao {
private JdbcTemplate jdbcTemplate;
private SimpleJdbcInsert memberInsert;
private SimpleJdbcCallOperations memberFindCall;
@Autowired
public void init(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.memberInsert = new SimpleJdbcInsert(dataSource).withTableName("member");
this.memberFindCall = new SimpleJdbcCall(dataSource).withFunctionName("find_member");
}
}