NamedParameterJdbcTemplate
NamedParameterJdbcTemplate이 제공하는 메서드는 JdbcTemplate과 비슷하다.
하지만 sql문에서 파라미터로 값을 받는 방법에 차이가 있다.
JdbcTemplate은 인덱스 기반의 파라미터를 설정하는 반면에
NamedParameterJdbcTemplate는 이름 기반의 파라미터를 설정한다.
이름 기반의 파라미터를 입력받기 위해서는 두 가지 방법이 있다.
바로 Map과 SqlParameterSource를 이용하는 것이다.
아래 사진과 같이 각 메서드의 파라미터 유형을 보면 Map과 SqlParameterSource를 지원해주는 것을 볼 수 있다.
이 두 가지 방법에 대해 알아보자
Map사용
1. queryForObject
sql문에 따로 입력될 부분이 없을 경우 아무 값도 가지지 않는 Collections.emptyMap()을 넣어주면 된다.
public int getStudentNum() {
return jdbcTemplate.queryForObject("select count(*) from student"
, Collections.emptyMap()
, Integer.class);
}
sql문에 입력될 값이 있는 경우 Map을 만들어줘야 한다. 그리고 다음과 같이 Map의 <key, value>에 맞게 값을 넣어준다. 그리고 이 Map객체를 queryForObject의 파라미터 값으로 넣어주면 된다.
public Student getStudent(String name) {
Map<String, String> map = new HashMap<String, String>();
map.put("name", name);
return jdbcTemplate.queryForObject("SELECT * FROM student WHERE name = :name"
,map
, (rs,rowNum)-> {Student student = new Student();
student.setAge(rs.getInt("age"));
student.setName(rs.getString("name"));
return student;
});
}
위와 같이 key-value쌍이 단 하나인 경우에는 Collections.singletonMap을 사용해도 된다.
public Student getStudent(String name) {
Map<String, String> map = Collections.singletonMap("name", name);
return jdbcTemplate.queryForObject("SELECT * FROM student WHERE name = :name"
,map
, (rs,rowNum)-> {Student student = new Student();
student.setAge(rs.getInt("age"));
student.setName(rs.getString("name"));
return student;
});
}
여기서 궁금증이 생겼다. Map에 String형과 int형을 모두 저장하고 싶을 땐 어떻게 해야 할까?
아래 코드처럼 Map 생성시 value의 값을 Object형으로 받으면 된다.
public Student getStudent(String name, int age) {
Map<String, Object> map = new HashMap<>();
map.put("name", name);
map.put("age",age);
return jdbcTemplate.queryForObject("SELECT * FROM student WHERE name = :name and age = :age"
,map
, (rs,rowNum)-> {Student student = new Student();
student.setAge(rs.getInt("age"));
student.setName(rs.getString("name"));
return student;
});
}
2. query
아래 코드는 여러 레코드를 가져오는 qeury에 적절한 예제는 아니지만 이해를 위해 작성해봤다.
queryForObject와 차이점은 메서드 반환타입을 List로 변경한 것 밖에 없다.
public List<Student> getStudents(String name, int age){
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("name", name);
paramMap.put("age",age);
return jdbcTemplate.query("select * from student where name = :name and age = :age"
, paramMap
, (rs, rowNum)-> {Student student = new Student();
student.setName(rs.getString("name"));
student.setAge(rs.getInt("age"));
return student;});
}
그래서 모든 학생의 정보를 가져오는 코드를 추가해봤다. sql문에 전달할 파라미터가 없으므로 Collections.emptyMap을 사용하였다.
public List<Student> getStudents(){
return jdbcTemplate.query("select * from student"
, Collections.emptyMap()
, (rs, rowNum)-> {Student student = new Student();
student.setName(rs.getString("name"));
student.setAge(rs.getInt("age"));
return student;});
}
3. update
update문에서 사용할 수 있는 insert, update, delete를 알아보자.
사용방법이 모두 비슷해서 코드로만 간단하게 작성하였다.
(1) insert
sql문만 잘 작성하면 다음과 같이 간단하게 작성할 수 있다.
public int insertStudent(Student student) {
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("name", student.getName());
paramMap.put("age", student.getAge());
int result = jdbcTemplate.update("insert into student values(:name, :age)"
, paramMap);
return result;
}
(2) update
public int updateStudent(String name, int age) {
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("name", name);
paramMap.put("age", age);
int result = jdbcTemplate.update("update student set age = :age where name = :name"
, paramMap);
return result;
}
(3) delete
public int deleteStudent(String name) {
Map<String, String> paramMap = Collections.singletonMap("name", name);
int result = jdbcTemplate.update("delete from student where name = :name"
, paramMap);
return result;
}
다음은 테스크 출력 코드와 결과이다.
SqlParameterSource
SqlParameterSource는 인터페이스이다. 그래서 구현한 클래스를 사용해서 파라미터 값을 전달해야한다. 구현된 클래스는 두 가지가 있다. 바로 BeanPropertySqlParameterSource와 MapSqlParameterSource이다. BeanPropertySqlParameterSource는 쿼리의 파라미터(:name)에 빈 객체의 프로퍼티 값을 이용해서 설정된다. 코드를 보면 이해가 된다.
각각의 메서드에 이 두 클래스를 적용해 보겠다.
1. queryForObject
메서드에서 Student객체를 받아서 그 객체를 BeanPropertySqlParameterSource의 파라미터 값으로 넣었고 변수명을 param이라고 지었다. queryForObject코드에 param을 넣어주면 student객체 내부에 설정된 name과 age에 접근해서 쿼리의 파라미터에 값을 넣어준다.
public Student getStudent(Student student) {
SqlParameterSource param = new BeanPropertySqlParameterSource(student);
return jdbcTemplate.queryForObject("select * from student where name = :name"
, param
,(rs,rowNum)->{
Student st = new Student();
st.setName(rs.getString("name"));
st.setAge(rs.getInt("age"));
return st;
});
}
MapSqlParameterSource는 Map과 비슷하다.
addValue를 통해 <key, value>쌍을 넣어주면 쿼리 파라미터로 사용 가능하다.
public Student getStudent(String name) {
MapSqlParameterSource param = new MapSqlParameterSource();
param.addValue("name", name);
return jdbcTemplate.queryForObject("select * from student where name = :name"
, param
,(rs,rowNum)->{
Student st = new Student();
st.setName(rs.getString("name"));
st.setAge(rs.getInt("age"));
return st;
});
}
2. update
(1) insert
insert문에서는 객체를 그대로 넣어주면 되므로 BeanPropertySqlParameterSource가 간결하다.
public int insertStudent(Student student) {
SqlParameterSource param = new BeanPropertySqlParameterSource(student);
int result = jdbcTemplate.update("insert into student values(:name, :age)"
, param);
return result;
}
MapSqlParameterSource를 이용했다.
public int insertStudent(Student student) {
MapSqlParameterSource param = new MapSqlParameterSource();
param.addValue("name", student.getName());
param.addValue("age", student.getAge());
int result = jdbcTemplate.update("insert into student values(:name, :age)"
, param);
return result;
}
(2) update
조건이 많은 쿼리인 경우 MapSqlParameterSource를 사용하는게 코드를 작성하기에 좋을 것 같다.
public int updateStudent(Student student) {
SqlParameterSource param = new BeanPropertySqlParameterSource(student);
int result = jdbcTemplate.update("update student set age = :age where name = :name"
, param);
return result;
}
public int updateStudent(String name, int age) {
MapSqlParameterSource param = new MapSqlParameterSource();
param.addValue("name", name);
param.addValue("age", age);
int result = jdbcTemplate.update("update student set age = :age where name = :name"
, param);
return result;
}
(3) delete
public int deleteStudent(Student student) {
SqlParameterSource param = new BeanPropertySqlParameterSource(student);
int result = jdbcTemplate.update("delete from student where name = :name"
, param);
return result;
}
public int deleteStudent(String name) {
MapSqlParameterSource param = new MapSqlParameterSource();
param.addValue("name", name);
int result = jdbcTemplate.update("delete from student where name = :name"
, param);
return result;
}
오늘의 결론
NamedParameterJdbcTemplate의 사용방법은 정말 다양하다. 자신의 상황에 맞게 코드를 사용하면 될 것 같다.
지금까지 JdbcTemplate과 NamedParameterJdbcTemplate의 사용법을 알아봤다.
다음에는 SimpleJdbcInsert 클래스에 대해 알아보겠다.
'Spring > 공부' 카테고리의 다른 글
[Spring MVC] Rest API, Web API 알아보기 (0) | 2021.02.07 |
---|---|
[Spring MVC] Spring Jdbc 정리 (SimpleJdbcInsert) (0) | 2021.02.05 |
[Spring MVC] Spring Jdbc 정리 (JdbcTemplate 예제) (0) | 2021.02.03 |
[Spring MVC] DataSource 이해하기 (0) | 2021.02.02 |
[Spring MVC] ContextLoaderListener 알아보기 (0) | 2021.02.02 |