Spring์์ DB์ ์ฟผ๋ฆฌ๋ฅผ ๋ ๋ฆฌ๊ธฐ ์ํด์ _jdbcTemplate_์ ์ฌ์ฉํ๊ณค ํ๋ค. ๋๊ตฐ๊ฐ๊ฐ ์ฟผ๋ฆฌ ํธํ๊ฒ ์์ฑํ๋ผ๊ณ ๋ง๋ค์๊ตฌ๋ ์ ๋๋ก ์๊ฐํ์๋ค. ํ์ง๋ง, ๊ณต๋ถ๋ฅผ ํ๋ค๋ณด๋ ์ด ์ด๋ฆ์๋ ์ ๋ง ํฌ๋ํฐ ์๋ฏธ๊ฐ ์๋ค๋ ๊ฒ์ ์๊ฒ ๋์๊ณ ๊ทธ ๊ตฌ์กฐ์ ๋ ํ๋ฒ ๊ฐํํ๊ฒ ๋์๋ค.
์ด์ ๋ถํฐ, _jdbcTemplate_๋ผ๋ ๊ฐ์ฒด ์งํฅ์ ์ผ๋ก DB์ ์ ๊ทผํ ์ ์๋ API๊ฐ ์ด๋ป๊ฒ ๋ง๋ค์ด์ก๋์ง ์ ๋ฆฌํด๋ณด๊ณ ์ ํ๋ค. ๊ทธ์ ์ ์์์ผ ํ๋ ๊ฐ๋ ์ธ ์์ง๋์ ๊ฒฐํฉ๋์ ๋ํด ๋จผ์ ์ดํด๋ณด์.
๋์ ์์ง๋(high cohesion)
๋์ ์์ง๋๋ ํ๋์ ๋ชจ๋, ํด๋์ค๊ฐ ํ๋์ ์ฑ ์, ๊ด์ฌ์ฌ์ ์ง์ค๋์ด ์๋ค๋ ๊ฒ์ด๋ค. ๊ทธ ์ธ์ ๊ด๋ จ ์๋ ์ฑ ์์ ์ฝํ์์ง ์๋ค. ์ด๋ ํด๋์ค ๋ ๋ฒจ ๋ฟ๋ง์ด ์๋๋ผ ํจํค์ง๋ ์ปดํฌ๋ํธ ๋ฑ์ ์์ญ์์๋ ๋ง์ฐฌ๊ฐ์ง๋ก ์ ์ฉ๋๋ค.
๋ํ ์์ง๋๊ฐ ๋๋ค๋ฉด ๋ณํ๊ฐ ์ผ์ด๋ ๋ ํด๋น ๋ชจ๋์์๋ง์ ๋ณํ๊ฐ ์ ์ผ ํฌ๋ค. ๋ง์ฝ ๋ค๋ฅธ ๋ชจ๋๋ ๊ฐ์ด ๋ณํ๋ค๋ฉด ์ด๋ ์์ง๋๊ฐ ๋ฎ๋ค๋ ๊ฒ์ด ๋๋ค.
๋ฎ์ ๊ฒฐํฉ๋(low Coupling)
๋ฎ์ ๊ฒฐํฉ๋๋ ๋ค๋ฅธ ๋ชจ๋๊ณผ์ ์์กด์ฑ ์ ๋์ด๋ฉฐ, ์ด๋ ๋์ ์์ง๋๋ณด๋ค ๋ ๋ฏผ๊ฐํ ์์น์ด๋ค. ๊ฒฐํฉ๋๊ฐ ๋ฎ๋ค๋ ๊ฒ์ ์ฑ ์์ฌ๊ฐ ๋ค๋ฅธ ๋ชจ๋๊ฐ์ ๋์จํ ์ฐ๊ฒฐ ํํ๋ฅผ ์ ์งํ๋ ๊ฒ์ ์๋ฏธํ๋ค.
์ฆ, ๊ด๊ณ๋ฅผ ์ ์งํ๋๋ฐ ์์ด์ ์ต์ํ์ ์ ๋ณด๋ง์ ์ฃผ๊ณ ๋๋จธ์ง ์ ๋ณด๋ ์ฃผ๋ฉด ์๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ๋ฎ์ ๊ฒฐํฉ๋๋ ํ๋์ ์ค๋ธ์ ํธ์์ ๋ณํ๊ฐ ์ผ์ด๋ ๋ ๊ด๊ณ๋ฅผ ๋งบ๊ณ ์๋ ๋ค๋ฅธ ์ค๋ธ์ ํธ์์๋ ์ด๋ฌํ ๋ณ๊ฒฝ์ ๋ํ ์๊ตฌ๊ฐ ์ ํ๋์ง ์๋ ์ํ์ด๋ค.
์ ๋ต ํจํด
์ ๋ต ํจํด์ ๋์์ธ ํจํด ์ค ํ๋๋ก ๋์ ์์ง๋์ ๋ฎ์ ๊ฒฐํฉ๋๋ฅผ ํ์ฑํ๋๋ฐ ๋์์ ์ฃผ๋ ํจํด์ด๋ค. ๋ฌผ๋ก ํ ํ๋ฆฟ ๋ฉ์๋ ํจํด๋ ์์ง๋๋ฅผ ๋์ด๊ณ ๋ฎ์ ๊ฒฐํฉ๋๋ฅผ ํ์ฑํ ์ ์๋ค. ํ์ง๋ง, ์ถ์ ํด๋์ค์์ ๋ณํ๋ฅผ ์ํ๋ ๋ถ๋ถ์ ์ถ์ ๋ฉ์๋๋ก ๋ง๋ค๊ณ , ์ผ์ผ์ด ์์์ ํตํด ๋ฉ์๋๋ฅผ ๊ตฌํํด์ผ ํด์ ๊ต์ฅํ ๋ฒ๊ฑฐ๋กญ๋ค.
๋ฐ๋ผ์ ๋์ฑ ์ ์ฐํ๊ณ ํ์ฅ์ฑ ๋๋๋ก ๋ง๋ค์ด์ง ๊ฒ์ด ๋ฐ๋ก ์ ๋ต ํจํด์ด๋ค. ์ ๋ต ํจํด์ ํ ๋ง๋๋ก ์ค๋ช ํ์๋ฉด "ํด๋ผ์ด์ธํธ๊ฐ ์ ๋ต ์ค๋ธ์ ํธ๋ฅผ ์ ํํ์ฌ ์ปจํ ์คํธ๊ฐ ํ์ฉํ ์ ์๋๋ก ํ๋ ๊ฒ"์ด๋ผ๊ณ ๋งํ ์ ์๋ค.
์ฌ๊ธฐ์ ๋งํ๋ ์ปจํ ์คํธ์ ์ ๋ต์ ๋ค์๊ณผ ๊ฐ์ด ์ ์ํ๋ค.
- ์ ๋ต(strategy) : ํ์์ ๋ฐ๋ผ ๋ณํ๋ ๋ถ๋ถ
- ์ปจํ ์คํธ(context) : ๋ณํ์ง ์๋ ๋ถ๋ถ
์ฆ, ์ค๋ธ์ ํธ๋ฅผ ๋๋ก ๊ตฌ๋ถํ๊ณ ํด๋์ค ์์ค์์ ์ธํฐํ์ด์ค๋ฅผ ํตํด์๋ง ์์กดํ๋ ๊ฒ์ด๋ค.
ํด๋ผ์ด์ธํธ
public class Client{
public void methodOfClient(){
Context context = new Context();
Strategy_Interface strategy = new Strategy_Implement();
context.contextWithStrategy(strategy);
}
}
ํด๋ผ์ด์ธํธ์์๋ ๋ณํ์ง ์๋ ์ปจํ ์คํธ๋ฅผ ํตํด์ ์ ๋ต์ ์ํํ๋ค.
์ปจํ ์คํธ
public class Context {
public void contextWithStrategy(Strategy_Interface st){
}
}
์ปจํ ์คํธ์์๋ ์ผ์ ํ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๊ณ ํ๋ํ๋๋ฐ, ์ด๋ ์ฃผ์ ๋ฐ์ ์ ๋ต์ ์ฌ์ฉํ๋ค. ์ปจํ ์คํธ๋ ์ ๋ต ์ธํฐํ์ด์ค๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฐ๊ธฐ ๋๋ฌธ์ ๊ฐ์ฒด์ ํ์๋ฅผ ๋์ ์ผ๋ก ๋ฐ๊ฟ ์ ์๋ค๋ ์ฅ์ ์ด ์๋ค.
์ ๋ต
public interface Strategy_Interface {
public void action();
}
public class Strategy_Implement {
@Override
public void action(){
}
}
์ ๋ต ์ธํฐํ์ด์ค์ ์ด๋ฅผ ์์ ๋ฐ์ ๊ตฌ์ฒดํ๋ ํด๋์ค๋ฅผ ํตํด์ ํ๋ก๊ทธ๋จ ์์ ๋ก์ง์ด ๋ฐ๋์ด๋ ์ ์ฐํ๊ฒ ์์ ํ ์ ์๋ค. ๋ฐ๋ผ์ OCP ์์น์๋ ์๋ฐ๋์ง ์์ ์ ์๋ค.
<ํ ๋น์ ์คํ๋ง> ์ ์ดํด๋ณด๋ฉด, JDBC์ ๋ณต์กํ ๋ก์ง์ ์ ๋ต ํจํด์ ํตํด์ ์ต์ ํ ๊ณผ์ ์ ์ฐพ์ ๋ณผ ์ ์๋ค.
ํ ํ๋ฆฟ/์ฝ๋ฐฑ ํจํด
์ ๋ต ํจํด์ ์ถ๊ฐํด์ผํ ์ ๋ต์ ๊ฐฏ์๊ฐ ๋ง์์ง๋ค๋ฉด ๊ทธ๋งํผ ์ ๋ต ํด๋์ค๋ฅผ ์๋กญ๊ฒ ์์ฑํด ์ฃผ์ด์ผ ํ๋ค. ๋ฟ๋ง ์๋๋ผ ์ ๋ฌํด์ผ ํ๋ ์ ๋ณด๊ฐ ๋ง๋ค๋ฉด ์ธ์๋ก ๋๊ฒจ ์ฃผ์ด์ผ ํ๋๋ฐ ์ด๋ ๊ฒ ๋๋ฉด ์ฝ๋๊ฐ ์๋นํ ์ง์ ๋ถํด์ง๋ค.
์ด๋ฅผ ๋ณด์ํ๊ธฐ ์ํ ๋ฐฉ์์ผ๋ก ๋ด๋ถ ํด๋์ค๋ฅผ ์ฌ์ฉํ๋ค๋๊ฐ ์ต๋ช ํด๋์ค๋ฅผ ์ฌ์ฉํ์ฌ _context_์ ์ ๋ฌํ๊ณค ํ๋๋ฐ, ์ด๋ฌํ ๋ฐฉ์์ ํจํด์ ํ ํ๋ฆฟ/์ฝ๋ฐฑ ํจํด์ด๋ผ๊ณ ํ๋ค.
์ ํํ๋ ์ธํฐํ์ด์ค๋ฅผ ์์ํ๋ ํด๋์ค๋ฅผ ๋ง๋ค์ง ์๊ณ , ์ต๋ช ๋ด๋ถ ํด๋์ค๋ฅผ ํ์ฉํ๋ค. ๋ํ ์ ๋ต ํจํด์ _context_์ _stretagy_๋ฅผ ํ ํ๋ฆฟ๊ณผ ์ฝ๋ฐฑ์ด๋ผ๋ ํ์ ๋ฐ๊พธ์ด ์ฌ์ฉํ๋ค.
ํ ํ๋ฆฟ๊ณผ ์ฝ๋ฐฑ์ ์ ํํ ์ญํ ๋ ๋ค์๊ณผ ๊ฐ๋ค.
- ํ ํ๋ฆฟ : ๊ณ ์ ๋ ํ ์์์ ๋ฐ๊ฟ ์ ์๋ ๋ถ๋ถ์ธ ์ฝ๋ฐฑ์ ๋ฃ์ด์ ์ฌ์ฉํ๋ค.
- ์ฝ๋ฐฑ : ์ต๋ช ๋ด๋ถ ํด๋์ค๋ก ๊ตฌ์ฑ๋๋ฉฐ _ํน์ ๋ก์ง_์ ๋ด์ ๋ฉ์๋๋ฅผ ์คํํ๊ธฐ ์ํ ์ค๋ธ์ ํธ์ด๋ค.
ํด๋ผ์ด์ธํธ
public class Client{
public void methodOfClient(){
Template template = new Template();
Callback temp_Callback = new Callback(){
@Override
public int calculate(int A, int B){
return ...
}
};
template.template_Method(temp_Callback, ๋ค๋ฅธ ์ ๋ณด ... etc);
}
}
ํด๋ผ์ด์ธํธ๋ _template_์ _callback_์ ์ฃผ์ ํ๋ค. ์ด์ ๊ฐ์ด ํด๋ผ์ด์ธํธ๊ฐ ์ฝ๋ฐฑ ์ค๋ธ์ ํธ๋ฅผ ๋ง๋ค๊ณ , ํ ํ๋ฆฟ์ ์ ๋ฌํ๋ ๊ฒ์ ๋ฉ์๋ ๋ ๋ฒจ DI์ด๋ค. ์ผ๋ฐ์ ์ธ DI๋ ํ ํ๋ฆฟ์ ์ธ์คํด์ค ๋ณ์๋ฅผ ๋ง๋ค๊ณ , ์ฌ์ฉํ ์์กด ์ค๋ธ์ ํธ๋ฅผ ์์ ์ ๋ฉ์๋๋ฅผ ํตํด์ ๋ฐ์ ์ ์๋ค.
ํ ํ๋ฆฟ
public class Template {
public int template_Method(int Callback callback, T ๋ค๋ฅธ ์ ๋ณด){
int A = &*%;
int B = !@#$%;
int result = callback.calculate(A, B);
}
}
์ด์ ํ ํ๋ฆฟ์์ ์ฝ๋ฐฑ ์ค๋ธ์ ํธ๋ฅผ ๊ฐ์ง๊ณ ์ผ์ ํ ๋ก์ง์ ์ํํ๋ฉด ๋๋ค.
์ฝ๋ฐฑ ์ธํฐํ์ด์ค
public interface Callback {
public int calculate(int A, int B);
}
์ฝ๋ฐฑ ์ธํฐํ์ด์ค๋ ์ผ๋ฐ์ ์ผ๋ก ๋จ์ผ ๋ฉ์๋๋ง์ ๊ฐ์ง๋ค. ํ ํ๋ฆฟ์ ์์ ํ๋ฆ ์ค, ํน์ ๊ธฐ๋ฅ์ ์ํํ๊ธฐ ์ํด ํ ๋ฒ๋ง ํธ์ถ๋๋ ๊ฒฝ์ฐ๊ฐ ๋๋ค์์ด๊ธฐ ๋๋ฌธ์ด๋ค.
ํญ์ ์ฝ๋ ํ๋ฆ์์ ์ค๋ณต๋๋ ์ฝ๋๊ฐ ๋ฐ์ํ์ ๋๋ ์ฝ๋๋ฅผ ๋ถ๋ฆฌํด๋ณผ ๋ฐฉ๋ฒ์ ์๊ฐํ์ฌ์ผ ํ๋ค. ๋ฉ์๋๋ก ๋ถ๋ฆฌํ ์๋ ์๊ณ , ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ด์ ๋ ์ฑ ์ ๋ต ํจํด์ ์ฌ์ฉํด DI๋ฅผ ํด์ค ์๋ ์๋ค. ํน์ ๋ฐ๋๋ ๋ถ๋ถ์ด ์ฌ๋ฌ ๊ฐ๊ฐ ๋์จ๋ค๋ฉด ํ ํ๋ฆฟ/์ฝ๋ฐฑ ํจํด์ ์ ์ฉํ ์ ์๋ค. ์ค์ํ ๊ฒ์ ์ค๋ณต๋ ์ฝ๋์ ๋ํด์ ๊ทธ๋ฅ ๋ ๋์ง ๋ง๊ณ ์ด๋ป๊ฒ ํ๋ฉด ์ต์ ํํ ์ ์์ ์ง ๊ณ ๋ฏผํด์ผ ํ๋ค๋ ๊ฒ์ด๋ค.
๋ง์ฝ ํ ํ๋ฆฟ/์ฝ๋ฐฑ ํจํด์ ์ ์ฉ์ํจ๋ค๊ณ ํ ๋, ๊ณ ๋ คํด์ผ ํ ์ ์ ๋ฐ๋๋ ๋ถ๋ถ๊ณผ ๋ฐ๋์ง ์๋ ๋ถ๋ถ์ด๋ค. ๋ฐ๋๋ ๋ถ๋ถ์ ์ฝ๋ฐฑ์ ๋ด์ ๊ฒ์ด๊ณ , ๋ฐ๋์ง ์๋ ์ฝ๋ ํ๋ฆ์ ํ ํ๋ฆฟ์ ๋ด์์ผ ํ ๊ฒ์ด๋ค. ๊ทธ๋ฆฌ๊ณ ์ด์ ๋ฐ๋ผ ์ฝ๋ฐฑ ํจ์๊ฐ ํ ํ๋ฆฟ์ผ๋ก ์ ํด ์ค ๋ด์ฉ์ ๊ดํด์๋ ์ ๋๋ก ํ์ ํ๋ ๊ฒ์ด ํ์ํ๋ค.
Spring์ jdbcTemplate
Spring์ _jdbcTemplate_๋ ํ ํ๋ฆฟ/์ฝ๋ฐฑ ํจํด์ ์ฌ์ฉํ๋ค. ์ผ๋ฐ์ ์ธ jdbc๋ฅผ ์ฌ์ฉํ๊ธฐ์๋ ๊ณ ๋ คํด์ผ ํ ์ ์ด ๋๋ฌด ๋ง๊ธฐ ๋๋ฌธ์ด๋ค.
๐ค jdbcTemplate๊ฐ ํ๋ ์ผ?
1๏ธโฃ Connection์ ์ด๊ณ ๋ซ๋๋ค.
2๏ธโฃ Statement๋ฅผ ์ค๋นํ๊ณ ๋ซ๋๋ค.
3๏ธโฃ Statement๋ฅผ ์คํํ๋ค.
4๏ธโฃ ResultSet Loop๋ฅผ ์ฒ๋ฆฌํ๋ค.
5๏ธโฃ Exception์ ์ฒ๋ฆฌํ๊ณ ๋ฐํํ๋ค.
6๏ธโฃ Transaction์ ์ฒ๋ฆฌํ๋ค.
_jdbcTemplate_๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ๊ฐ๋ฐ์๋ ์ฟผ๋ฆฌ๋ฅผ ์ง๋ ์ผ ์ด์ธ์ ์์ ์ ๋ํด์๋ ์๊ด ์ฐ์ง ์์๋ ๋๋ค. ๋ํ DB Connection์ ํ๋๋ฐ ์์ด ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ผ๋ ์ ์ด์ง๋ ๊ทธ ์ฅ์ ์ด ๋งค์ฐ ํฌ๋ค.
_jdbcTemplate_๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ๋ง์ฐฌ๊ฐ์ง๋ก DI๋ฅผ ํตํด ์ฃผ์ ์ ์์ผ์ฃผ์ด์ผ ํ๋ค.
public class UserDao {
DataSource dataSource;
JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
...
Object with Count
_jdbcTemplate_์ queryForObject_๋ ๋จ์ผ ๊ฐ์ฒด๋ฅผ ์กฐํํ ์ ์๋ค.
int rowCount = jdbcTemplate.queryForObject("select count(*) from customers", Integer.class);
Object with Parameter
_queryForObject_์ 3 ๋ฒ์งธ ๋งค๊ฐ๋ณ์๋ฅผ ํตํด ํ๋ผ๋ฏธํฐ๋ฅผ ์ง์ ํ ์ ์๋ค.
String lastName = jdbcTemplate.queryForObject("select last_name from customers where id = ?", String.class, id);
Object with RowMapper
_queryForObject_์ ๋ ๋ฒ์งธ ๋งค๊ฐ๋ณ์์ _RowMapper_๋ฅผ ์ ๋ฌํ๋ค๋ฉด, ๊ฐ์ฒด๋ก์จ ๊ฐ์ ๋ฐ์ ์ ์๋ค.
Customer customer = jdbcTemplate.queryForObject(
"select id, first_name, last_name from customers where id = ?",
(resultSet, rowNum) -> {
Customer customer = new Customer(
resultSet.getLong("id"),
resultSet.getString("first_name"),
resultSet.getString("last_name")
);
return customer;
}, id);
_query_๋ฌธ์ ์ฌ์ฉํ๋ค๋ฉด, List๋ก์จ๋ ๋ฐ์ ์ ์๋ค.
List<Customer> customers = jdbcTemplate.query(
"select id, first_name, last_name from customers",
(resultSet, rowNum) -> {
Customer customer = new Customer(
resultSet.getLong("id"),
resultSet.getString("first_name"),
resultSet.getString("last_name")
);
return customer;
});
update
INSERT, UPDATE, DELETE๋ ๋ชจ๋ _update_ ๋ฉ์๋๋ฅผ ํตํด์ ์ํํ ์ ์๋ค.
jdbcTemplate.update("insert into customers (first_name, last_name) values (?, ?)", customer.getFirstName(), customer.getLastName());
jdbcTemplate.update("delete from customers where id = ?", Long.valueOf(id));
KeyHolder
์ด๊ฑด ์ข ๊ท์ฐฎ๊ธฐ๋ ํ๋ฐ, ๊ฐ์ ธ์จ ํ ์ด๋ธ์ PK๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด์ _KeyHolder_๋ผ๋ ๊ฒ์ ํตํด ๊ฐ์ ธ์์ผ ํ๋ค.
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(connection -> {
PreparedStatement ps = connection.prepareStatement(
"insert into customers (first_name, last_name) values (?, ?)",
new String[]{"id"});
ps.setString(1, customer.getFirstName());
ps.setString(2, customer.getLastName());
return ps;
}, keyHolder);
Long id = keyHolder.getKey().longValue();
References