1. Application Architecture
- 서버와 클라이언트 사이에 TCP라는 프로토콜이 존재하여 커넥션을 만들어주어 통신을 가능하게 해 준다.
- 같은 개념으로 서버와 DB사이에도 커넥션을 만들어주어야만 통신이 가능하다.
2. Data Access Layer
- 요구되는 라이브러리
- JDBC Template (Spring에서 제공되는 클래스): spring-jdbc
- DataSource (Apache): commons-dbcp
- JDBC Driver: mysql (mySQL)-connector-java
- JDBC Template를 사용하려면 DataSource가 주입되어야 한다.
ex) A대학의 DataSource를 만들어서 JDBC Template에 주입하면 A대학 DB에 접근하게 된다.
- Maven을 사용하여 라이브러리를 다운로드한다.
ex)
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.1.1</version>
</dependency>
Maven의 장점:
- 라이브러리와 라이브러리 사이에 의존성이 존재하는 경우 -> 의존된 라이브러리까지 한꺼번에 가져온다.
-> 라이브러리 관리가 편리(자동으로 원격 저장소에 있는 라이브러리를 로컬 저장소로 가져온다.)
3. Configuring Data Source
- Database의 데이터로 작업을 하기 위해서는 Datasource로부터 Database의 커넥션을 얻어야 한다.
- DataSource의 implementation 예시
- BasicDataSource
- PoolingDataSource
- SingleConnectionDataSource
- DriverManagerDataSource
Apache Common DBCP 라이브러리 안에 있는 BasicDataSource.class
-> Database 커넥션 풀을 제공해준다.
그림 설명:
- Thread Pool이란?
- 요청이 올 때마다 Thread를 만들고 작업이 끝나면 삭제하고를 반복하면 오버헤드 발생
- Thread를 미리 만들어 놓고 request가 들어올 때마다 할당해주고 request가 끝나면 다시 Thread를 대기시킨다.
- Thread를 만드는 것은 Stack 메모리를 사용하는 것 -> Thread를 미리 너무 많이 만들어 놓으면 메모리 낭비
-> 적절한 양의 Thread만 생성해야 함
- Tomcat은 Thread Pool 방식으로 request가 들어올 때마다 각 request에 하나의 Thread를 할당해준다.
- DB 커넥션 풀(DB Connection Pool)이란?
- Database Connection을 열고 닫고 할 때의 오버헤드를 줄이기 위해 사용
- Thread pool처럼 미리 Connection들을 만들어 놓는다.
- 만들어 놓은 Connections 보다 더 많은 request가 들어오면 maxWait만큼 BLOCK 시킨다.
- Apache Common DBCP를 사용하면 Connection Pool 사용
XML 파일에 DataSource bean을 등록(설정)
- root에 바로 값을 넣는 hard coding을 하지 말아야 한다.
- properties 파일을 만들어 db 연결에 필요한 정보(username, password, DriverClassName, url...)를 관리한다.
- properties는 이름을 마음대로 정할 수 있기 때문에 XML에 placeholder에 위치를 넣어주어야 적용된다.
예시)
//jdbc.properties
jdbc.username= kwon
jdbc.password= tiger
jdbc.driverClassName = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/testDB
//beans.xml
<context:property-placeholder
location="패키지명/jdbc.properties"/>
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name= "driverClassName" value= "${jdbc.driverClassName}"/>
<property name= "url" value= "${jdbc.url}"/>
<property name= "username" value= "${jdbc.username}"/>
<property name= "password" value= "${jdbc.password}"/>
</bean>
4. Data Access Object(DAO)
- 관계형 데이터베이스에 액세스 하기 위한 객체 지향 API를 제공하는 객체
- DAO는 Application Service 객체와 데이터베이스 간의 중개자 역할을 한다.(맨 위 그림 참고)
예시)
package ;
@Component("offersDao")
public class OfferDAO{
private JdbcTemplate jdbcTemplateObject;
@Autowired
public void setDataSource(DataSource dataSource){
this.jdbcTemplateObject = new JdbcTemplate(dataSource);
}
public int getCount(){
return jdbcTemplate.queryForInt("select count(*) from testTable");
}
}
- @Autowired로 dataSource를 DI(의존성 주입)하고 jdbcTemplateObject에 dataSource를 넣어 객체로 만든다.
- DAO는 jdbcTemplateObject를 사용하여 DB를 제공한다.
5. Spring JDBC Framework
- Plain JDBC: 예외처리, database 커넥션 열고 닫기 등의 불필요한 코드를 작성해야 한다.
- Spring JDBC: 모든 로우 레벨을 관리
- 커넥션 열기
- SQL문 준비하고 실행
- 예외처리
- 트랜잭션 처리
- 커넥션 닫기
JDBC 데이터베이스 액세스의 기초를 형성하기 위한 접근 방식을 선택하기 위한 여러 옵션들 존재
- JdbcTemplate
- JDBC 프레임 워크의 중앙 클래스
- 모든 데이터베이스 통신 및 예외 처리 관리- SQL 쿼리를 실행
- ResultSet에 대한 반복 및 리턴된 매개 변수 값 추출
- JDBC 예외를 포착하여 "org.springframework.dao"패키지에 정의된 보다 유익하고 일반적인 예외 계층 구조로 변환
- NamedParameterJdbcTemplate
- SimpleJdbcTemplate
- SimpleJdbcInsert and SimpleJdbcCall
- RDBMS Objects including MappingSqlQuery, SqlUpdate and StoredProcedure
예시)
package ;
import java.sql.ResultSet;
@Component("offersDao")
public class OfferDAO{
private JdbcTemplate jdbcTemplateObject;
@Autowired
public void setDataSource(DataSource dataSource){
this.jdbcTemplateObject = new JdbcTemplate(dataSource);
}
public List<Offer> getOffers() {
return jdbcTemplateObject.query("select * from offers", new RowMapper<Offer>(){
public Offer mapRow(ResultSet rs, int rowNum) throws SQLException{
Offer offer = new Offer();
offer.setId(rs.getInt("id"));
offer.setName(rs.getString("name"));
return offer;
}
});
}
}
- jdbc Template은 DB에서 레코드를 받아 DAO에 객체를 넘겨준다. -> 객체로 mapping 해주는 부분 필요
But!! Spring에서 mapping을 해줄 수 없다 -> mapping 부분은 개발자가 해야 된다.
-> mapping을 위한 인터페이스 필요
-> Spring에서 RowMapper라는 인터페이스를 정의해두었다.
(Spring은 mapping을 할 순 없지만 자신이 알아볼 수 있도록 인터페이스를 정의해둠)
- 인터페이스는 객체를 만들 수 없지만 인터페이스와 같은 이름을 사용하기 위해 익명 클래스 개념을 사용
-> 위 코드에서 new RowMapper 부분에서 RowMapper는 인터페이스 이름이지만 코드를 축약시키기 위해서 익명 클래스를 사용 (바로 mapRow를 재정의하여 사용) -> 어차피 한번 쓰고 안 쓸 클래스이기 때문에 정의할 필요성 x
참고) sql문으로 record가 여러 개 넘어오면 그만큼 mapRow메서드가 호출된다.
@Component
//이전까지 DI를 위한 Bean 설정
<bean id="offersDao" class="패키지명/OfferDAO">
<property name="dataSource" ref="dataSource"/>
</bean>
//@Component를 사용하는 경우
//기존 bean 설정 코드를 지우고
<context:component-scan base-package="패키지명">
</comtext:component-scan>
- component scan 설정을 해주면 해당 package에 들어있는 모든 @Component가 달린 클래스들을 빈으로 등록하고
기존 XML 설정 코드처럼 @Autowired가 달린 변수에 의존성 주입을 시켜준다.
JdbcTemplate class Usage
- Querying for an integer
String SQL = "select count(*) from Student";
int rowCount = jdbcTemplateObject.queryForObject( SQL, Integer.class); - Querying for an String
String SQL = "select name from Student where id =?";
String name = jdbcTemplateObject.queryForObject(SQL, new Object []{10}, String.class);
String SQL = "select name from Student where id =?";
String name = jdbcTemplateObject.queryForObject(SQL, 10, String.class); - Querying and returning an object
String SQL = "select * from Student where id = ?";
Student student = jdbcTemplateObject.queryForObject(SQL,
new Object[]{10}, new StudentMapper());
public class StudentMapper implements RowMapper<Student> {
public Student mapRow(ResultSet rs, int rowNum)
throws SQLException {
Student student = new Student();
student.setID(rs.getInt("id"));
student.setName(rs.getString("name"));
student.setAge(rs.getInt("age"));
return student;
- Querying and returning multiple objects
String SQL = "select * from Student";
List<Student> students = jdbcTemplateObject.query(SQL,
new StudentMapper());
public class StudentMapper implements RowMapper<Student> {
public Student mapRow(ResultSet rs, int rowNum)
throws SQLException {
Student student = new Student();
student.setID(rs.getInt("id"));
student.setName(rs.getString("name"));
student.setAge(rs.getInt("age"));
return student;
- Inserting a row into the table
String SQL = "insert into Student (name, age) values (?,?)";
jdbcTemplateObject.update( SQL, new Object []{"Zara", 11} ); - Updating a row into the table
String SQL = "update Student set name =? where id =?";
jdbcTemplateObject.update( SQL, new Object []{"Zara", 10} ); - Deleting a row from the table
String SQL = "delete from Student where id =?";
jdbcTemplateObject.update( SQL, new Object []{20} );
References
- https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/
- https://d2.naver.com/helloworld/5102792
'Spring > 이론' 카테고리의 다른 글
Spring Web Form (0) | 2020.03.25 |
---|---|
MVC(Model-View-Controller) (0) | 2020.03.17 |
관점 지향 프로그래밍(AOP, Aspect Oriented Programming) (0) | 2020.03.07 |
의존성 주입(Dependency Injection) (0) | 2020.03.05 |
JSP(Java Server Pages) (0) | 2020.03.05 |
댓글