구현하는 자세한 설명은 전편에 있음 ( http://winmargo.tistory.com/117 )

이번 글에서는 전편에 다못한 Statement 처리를 위한 다양한 메소드들의 사용법을 살펴보자.

메소드에 쿼리문에 값을 전달하는 방법에는  인덱스 방식과, 네임드 방식이 있다

인덱스는 전편에서도 했고, 쉽기때문에 넘어가고

여기서는 네임드 방식을 쓰겠다.

네임드 방식은 인덱스에서 쿼리에 ? 를 넣은것과같이, ':변수명 또는 :맵의키값' 형식으로 넣는다 .
':' 콜론을 붙이면 되는것이다.

NamedParameterJdbcTemplate 에는 이름 기반의 파라미터를 설정할 수 있도록 해준다.

그 방식에는 두가지 방식이 있는데,

1. Map 을 이용한 파라미터 값 설정

말 그대로 맵을 이용한다. 쿼리문내에 ':' 콜론을 이용해서 키값과 같이 써주고
맵을 인자로 넣어주면, 매핑된다.


2. SqlParameterSource 를 이용한 파라미터 값 설정( 실제는 BeanPropertySqlParameterSource 클래스)

SqlParameterSource 는 인터페이스이기 때문에 실제로 사용할때는 구현한 클래스를 사용한다.

그 클래스가 바로 BeanPropertySqlParameterSource  이다.

생성할 때 인자로 자바빈 클래스를 넣어주면, 자동으로 Bean 클래스 변수와 쿼리안의 : 콜론과 붙여쓰는 이름을

같게 해주면 자동으로 매핑된다.

(MapSqlParameterSource 클래스도 있긴한데 쓸일이 없을것같다.. 불편하다)




이제부터 볼 예제들은  SimpleJdbcTemplate 을 이용한 것이다.



아래 코드는 Map 방식과 BeanPropertySqlParameterSource가 다들어있는 아주 중요한 코드다.
눈 크게 뜨고 살펴보자!!
'
public int setReply(ItemBean itemBean, int originalNumber, int depth){
		
		
		int state = 0;
		
		int firstNumber = originalNumber - 1;
		
		itemBean.setArticle_num(firstNumber);
		
		int lastNumber = firstNumber - (firstNumber % 1000) + 1;
		
		paramSource = new BeanPropertySqlParameterSource(itemBean);
		
		Map map = new HashMap();
		
		map.put("first", firstNumber);
		
		map.put("end", lastNumber);
		
		
		//  - map 방식
		sql = "UPDATE margo SET article_num = article_num - 1 WHERE article_num BETWEEN :end AND :first";
		
		template.update( sql, map);	
		
	
				
		//  - sqlParameterSource 방식
		sql = "INSERT INTO margo " + 
			  "VALUES(:article_num, :id, :title, :body, :password, :count, :depth, sysdate, :fileName)";
		
		return template.update( sql, paramSource);
		
	} // setReply() end;
	
↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

23라인을 보면, 쿼리에 값을 주입할때, (BETWEEN :end AND :first) 라고 되어있다

바로 맵으로 end 와, first 키를 생성해 놓은것을, 키값을 콜론과 같이 쓰면

맵에서 자동으로 뽑아 쓴다.


그 다음은 31라인은 BeanPropertySqlParameterSource() 메소드를 이용해서 값을 주입하는 방식이다.

 13라인에서 paramSource에 생성자로 메소드 인자로 넘겨받은 자바빈 파일을 넣어주면,

자동으로 자바빈안의 변수와 값을 매핑 시켜준다.

위 두가지 방식인 네임드(이름기반) 파라미터방식은 여러모로 쓸모가 많을것 같다. 잘 배워두자~ 

 




아래는 간단한 컬럼하나 가지고오는 예제
_
	// 총글의 개수를 가지고온다. 안에 사용한 두 가지 코드는 결과는 동일하다.
	public int getArticleCount() {
	
		sql = "SELECT COUNT(*) FROM margo";
		
		
		// Object 로 리턴값을 명시해주고 컬럼 하나를 받아온다.
		totNum = template.queryForObject( sql, Integer.class);
		 

		// queryForInt 메소드를 써서 int값 만 받아올때 쓸 수 있다.
		totNum = template.queryForInt(sql);
		
		return totNum;
		
	}
	
 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

코드만 봐도 대충 알수있을 만큼 간단하다.
어떤 객체 하나를 받아올때는 QeuryForObject 를 쓰고, 리턴타입을 지정해주려면,
9라인의 방식을 쓴다. 여기서는 int 지만, 아래 예제에서 클래스를 쓰는법을 설명하겠다.
정수만 받을때는 13라인을 쓰면된다. 






QueryForObject 로 클래스(자바빈)를 리턴받는 법
<T> T
queryForObject(String sql, RowMapper<T> rm, Object... args) 
.
	public ItemBean getContent(final int contentNum) {
		
		sql = "SELECT * FROM margo WHERE article_num=?";
			
		// 익명클래스 이용한 방법.
		return template.queryForObject( sql, 
									
			new RowMapper(){
					
					@Override
					public ItemBean mapRow(ResultSet rs, int rowNum) throws SQLException{
						
						ItemBean itemBean = new ItemBean();
						
						itemBean.setArticle_num(rs.getInt("article_num"));
						itemBean.setId(rs.getString("id"));
						itemBean.setTitle(rs.getString("title"));
						itemBean.setBody(rs.getString("body"));
						itemBean.setCount(rs.getInt("hit"));
						itemBean.setDepth(rs.getInt("depth"));
						itemBean.setPassword(rs.getString("password"));
						itemBean.setWrite_date(rs.getTimestamp("write_date"));
						itemBean.setFileName(rs.getString("filename"));
					
						return itemBean;
					
					}// mapRow() end;
					
			}, // RowMapper 클래스 여기까지임.
			
			new Object[]{ contentNum });
		
	}
 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

익명클래스 방식을 이용해서 리턴 클래스를 지정해주고, ResultSet 을 이용해서 리턴받는 방법이다.

RowMapper클래스는 mapRow() 메소드를 오버라이드 해야된다.
(35라인은 무시, 코드하이라이트 버그같은데, 제네릭을 태그로인식해서 지맘대로 닫는코드를 생성...짜증난다 ㅡㅡ;) 






아래 코드는 UPDATE 메소드를 이용해서 DB에 자료를 Insert 하는 쓰는 법이다.
(SQL쿼리 update와 헷갈리면 안된다. 쓰는건 전부 update() 메소드다)
int update(String sql, Object... args)
public int setContent(ItemBean itemBean){
		
		int state = 0;
		
		String sql = "INSERT INTO margo VALUES(margo_sequence.NEXTVAL,?,?,?,?,?,?,sysdate, ?)";
		
		
		state = template.update( sql, 
							new Object[]{ itemBean.getId(),
											itemBean.getTitle(),
											itemBean.getBody(),
											itemBean.getPassword(),
											itemBean.getCount(),
											itemBean.getDepth(),
											itemBean.getFileName()});
		
		return state;
	}
	

↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

update() 메소드가 나왔는데, 
쿼리에 값 주입방식은 인덱스 기반 파라미터 방식으로 집어넣고 있다.
뭐...간단하다  .


YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST




SimpleJdbcTemplate 클래스는

JdbcTemplate 과 NamedParameterJdbcTemplate 을 합쳐 놓은 템플릿 클래스로서

이름 기반의 파라미터 설정인덱스 기반의 파라미터 설정을 모두 지원한다.

이름 기반의 파라미터를 설정할 때에는 Map과 SqlParameterSource 두 가지 방법을 모두 사용할 수 있다.

SimpleJdbcTemplate 클래스가 제공하는 주요메소드는 아래와 같다. 



Method Summary

<T> List<T> 
query(String sql, RowMapper<T> rm, Map<String,?> args)
<T> List<T>
query(String sql, RowMapper<T> rm, Object... args) 
<T> List<T>
query(String sql, RowMapper<T> rm, SqlParameterSource args) 




int queryForInt(String sql, Object... args) 
int queryForInt(String sql, SqlParameterSource args) 



List<Map<String,Object>> queryForList(String sql, Object... args)
List<Map<String,Object>> queryForList(String sql, SqlParameterSource args) 



<T> T
queryForObject(String sql, RowMapper<T> rm, Object... args) 
<T> T
queryForObject(String sql, RowMapper<T> rm, SqlParameterSource args)  



int update(String sql, Object... args)
int update(String sql, SqlParameterSource args) 



이렇게 받은 template을 처리해야될 방법에 따라 잘 만들어진 메소드를 고르기만 하면 된다.

가장 기본인 DB 에서 모든 글을 긁어온다음 list 를 만들어서 보여주는 걸 해보자.
나는  List query(String sql, RowMapper<T> rm, Object... args) 이놈을 골랐다!

그럼이제 리스트 를 보여주기위한 작업을 해보자.


1.  servlet.xml 에 SimpleJdbcTemplate 을 등록한다. (http://winmargo.tistory.com/116 참고)


2. 처리를 수행하는 구현클래스에서 SimpleJdbcTemplate 을 이용해서 Statement 작업을 구현하면 끝이다.
  


구현클래스를 보자
     private SimpleJdbcTemplate template = null;
	
   
	
	
	//모든글을 몽땅 가져온다.
	@Override
	public List getArticles(int index) {
		
						
		sql =  "SELECT * FROM (SELECT ROWNUM rnum,A.* FROM " +
				"(SELECT * FROM margo ORDER BY article_num DESC) A ) "
				+ "WHERE rnum BETWEEN ? AND ?";
	
					
			
		return template.query( sql, 
				
				   				   new ItemBeanRowMapper(),
								   new Object[]{ index, (index + 10)});
		
	}
	
 

코드를 보면 17 라인에 return 값에 simpleJdbcTemplate을 줬다. 리턴값이 List


첫 번째 인자에 sql쿼리를 넣고,

두번째에 3라인에 선언한 ItemBeanRowMapper() 를 넣어주고 있다.(아래에서 자세히)

세 번째 인자에는 쿼리문 안에 있는 '?' 에 대응되어 들어갈 값 2개가 있다. ? 순서와 개수에 맞게 넣어주면 된다.(이것이 인덱스 방식이다)
  
  - 쿼리에 값을 넣는 방법은 두가지가 있는데, 인덱스 파라미터 방식과, 네임드 파라미터(이름 기반) 방식이 있다.
     
     ? 에 순서대로 대입하는 방식은 Index 기반 파라미터 방식이고,
     
      넣어줄 값을 들고있는 맵이나, 빈클래스의 변수을 ':' 콜론과 같이 쓰면 값이 들어가는데
     이 방식이 이름 기반의 파라미터 방식이다.  




기본적인 동작 방식은 template 이 sql쿼리문에 값을 넣고, Statement 처리를 한후

19라인에 있는 ItemBeanRowMapper()  클래스를 이용해서 ResultSet 을 처리한후

리턴되어오는 어떤 클래스(여기서는 Bean파일이다) 를  List 에 자동으로 담은후

그 List 를 리턴해준다.


여기서 중요한건 19라인에 ItemBeanRowMapper()  클래스 이다.

이 클래스는 위설명과 같이 쿼리수행후 리턴된 다수개의 레코드들을 모은 ResultSet에서

레코드컬럼과, 자바빈 변수를 Mapping 시켜

한 개의 레코드를 하나의 자바빈 으로 만들어서 return 시켜주면

Template 이 자동으로 List 에 담아서 Template 수행후 마지막으로 리턴 시킨다.

ItemBeanRowMapper() 클래스는 RowMapper<T> 를 구현해야한다.


ItemBeanRowMapper 클래스를 보자


package Spring;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.jdbc.core.RowMapper;

public class ItemBeanRowMapper implements RowMapper {

	
	
	@Override
	public ItemBean mapRow(ResultSet rs, int rowNum) throws SQLException {
		
		ItemBean itemBean = new ItemBean();
		
		String str ="";
				
		itemBean.setArticle_num(rs.getInt("article_num"));
		itemBean.setId(rs.getString("id"));
		itemBean.setTitle(rs.getString("title"));
		itemBean.setCount(rs.getInt("hit"));
		itemBean.setDepth(rs.getInt("depth"));
		itemBean.setWrite_date(rs.getTimestamp("write_date"));
		itemBean.setFileName(rs.getString("filename"));
		
		int cnt = itemBean.getDepth();
		
		while( cnt > 0){
			
			str += "    ";
			cnt--;
		}

		itemBean.setSpace(str);
		
		return itemBean;
	}

}

↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
메소드 코드를 대충보면 딱 알수 있을만큼 간단하다.  

mapRow(ResultSet rs, int rowNum)

메소드를 오버라이딩 하면서 인자로  ResultSet 과 정수하나를 주는데

뒤에정수는 레코드 개수이다.

사용할 일이 있을때 사용하면된다.

빈파일에 컬럼을 매핑시킨후, 빈파일을 리턴하면

template 이 자동으로 List 에 쑥쑥 넣는다.


수가지의 방식이 있는데, 일단은 제일 요긴하고 잘쓰일 방법으로 구현해보았다.


다음편에는 다른 여러가지 구현방식을 알아보겠음



YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST