4.1 데이터 액세스 층과 스프링
- 데이터 액세스 층은 데이터 액세스 처리를 비즈니스 로직 층에서 분리하여 따로 만들어준 층
- 데이터 액세스 처리와 비즈니스 로직이 섞여있으면 유지보수가 어렵고, 코드 가독성이 떨어진다.
4.1.1 DAO 패턴이란?
- DAO 패턴은 데이터의 취득, 변경 등 데이터 액세스 처리를 DAO라고 하는 오브젝트로 분리하는 패턴
- 데이터 액세스 방식이 바뀌어도 DAO만 변경하면 된다.
- DAO 클래스는 DB의 테이블별로 만든다.
4.1.2 자바의 데이터 액세스 기술과 스프링의 기능
- 자바의 데이터 액세스 기술
(1) JDBC
(2) 하이버네이트 & JPA 등 고성능 ORM 프레임워크
(3) MyBatis(iBATIS)
(4) 독자 개발한 프레임 워크 등
- 스프링은 여러 자바의 데이터 액세스 기슬과 연계 기능을 제공한다.
- 스프링과 연계함으로써 얻을 수 있는 장점
(1) 데이터 액세스 처리를 간결하게 기술할 수 있다.
(2) 스프링이 제공하는 범용적이고 체계적인 데이터 액세스 예외를 이용할 수 있다.
(3) 스프링 트랜잭션 기능을 이용할 수 있다.
4.1.3 범용 데이터 액세스 예외 처리
4.1.4 데이터 소스
- 데이터 액세스 기술의 종류와 상관없이 DB 접속은 필요하다.
- DB 접속을 관리해주는 것이 데이터 소스
4.2 스프링 JDBC
- 스프링 JDBC는 JDBC를 래핑한 API를 제공하고 JDBC보다 간결하게 사용할 수 있는 스프링의 기능
4.2.1 JDBC를 직접 사용한 경우의 문제점
- 대량의 소스 코드를 기술
- 다양한 에러 원인을 파악하기 위한 코딩 필요
- DB 제품마다 에러코드가 다름 -> 코드의 일관성 유지 어려움
4.2.2 스프링 JDBC의 이용
- JDBC를 래핑한 API 제공 -> 소스 코드 단순화
- JDBC를 직접 사용할 때 발생하는 장황한 코드를 숨겨준다.
4.2.3 Template 클래스
- 가장 중요한 클래스
(1) JdbcTemplate
(2) NamedParameterTemplate
queryForObject : 하나의 결과 레코드 중에서 하나의 컬럼 값을 가져옴
queryForMap : 하나의 결과 레코드 정보를 Map 형태로 매핑
queryForList : 여러 개의 Map 형태의 결과 레코드 다룸
query : 여러 개의 레코드를 객체로 변환 후 처리
update : 데이터의 변경 (insert, update, delete)
4.2.4 SELECT 문(도메인으로 변환하지 않을 때)
queryForObject 메소드
- 취득 결과를 도메인으로 변환하지 않는 경우라는 것은, 레코드의 건수를 취득하거나 1 레코드 중에서 특정 컬럼만 취득하는 등의 단순하게 취득하는 경우
int count = jdbcTemplate.queryForObject(
"SELECT COUNT(*) FROM PET", Integer.class);
int count2 = jdbcTemplate.queryForObject(
"SELECT COUNT(*) FROM PET WHERE OWNER_NAME = ?", Integer.class, ownerNm);
- queryForObject 메소드의 리턴값은 Object지만, 제네릭에 따라서 2번째에 준 인수에서 지정한 형으로 리턴된다.
- String이나 Date도 가능하다.
queryForMap 메소드
- 컬럼 하나가 아니라 한 레코드의 값을 가져오는 경우 Map으로 가져온다.(컬럼 이름이 Key)
Map<String, Object> pet = jdbcTemplate.queryForMap(
"SELECT * FROM PET WHERE PET_ID = ?", id);
- 만약 PET_NAME 컬럼의 값을 참조하고 싶다면
String petNm = (String)pet.get("PET_NAME");
queryForList 메소드
- 여러 레코드의 Map 데이터를 가져올 때 사용한다.
List<Map<String, Object>> petList = jdbcTemplate.queryForList(
"SELECT * FROM PET WHERE OWNER_NAME = ?", ownerNm);
4.2.5 SELECT 문(도메인으로 변환할 때)
queryForObject 메소드
- 익명클래스를 사용했을 때
Pet pet = jdbcTemplate.queryForObject(
"SELECT * FROM PET WHERE PET_ID = ?"
, new RowMapper<Pet>() {
public Pet mapRow(ResultSet rs, int rowNum) throws SQLException {
Pet p = new Pet();
p.setPetId(rs.getInt("PET_ID");
p.setPetName(rs.getString("PET_NAME");
return p;
}
}
, id);
- 익명클래스를 사용하지 않았을 때는 생략
query 메소드
- 여러 레코드를 가져올 때 사용한다.
List<Pet> petList = jdbcTemplate.query(
"SELECT * FROM PET WHERE OWNER_NAME = ?"
, new RowMapper<Pet>() {
Pet p = new Pet();
p.setPetId(rs.getInt("PET_ID");
p.setPetName(rs.getString("PET_NAME");
}
)
4.2.6 INSERT/UPDATE/DELETE 문
- 데이터 삽입, 수정, 삭제 시 사용
// insert
jdbcTemplate.update(
"INSERT INTO PET (PET_ID, PET_NAME) VALUES (?, ?)"
, pet.getPetId(), pet.getPetName()
);
// update
jdbcTemplate.update(
"UPDATE PET SET PET_NAME = ? WHERE PET_ID = ?"
,pet.getPetName(), pet.getPetId()
);
// delete
jdbcTemplate.update("DELETE FROM PET WHERE PET_ID = ?", pet.getPetId());
- jdbcTemplate.update 시 리턴 값은 int로 갱신된 레코드 수
4.2.7 NamedParameterJdbcTemplate
- ?(플레이스홀더)를 사용할 경우 파라미터 순서가 중요하다. 숫자가 많아지면 분명히 한번 씩 틀린다.
- 이럴 때 NamedParameterJdbcTemplate를 사용한다.
namedParameterJdbcTemplate.update(
"INSERT INTO PET(PET_ID, PET_NAME) VALUES (:PET_ID, :PET_NAME)"
,new MapSqlParameterSource()
.addValue("PET_ID", pet.getPetId())
.addValue("PET_NAME", pet.getPetName())
);
4.3 Spring Data JPA
- 따로 JPA 카테고리가 있으니 참고!
https://devhooney.tistory.com/33
'개발 > Java&Kotlin' 카테고리의 다른 글
[Spring] 비즈니스 로직 층의 설계와 구현 (0) | 2022.07.21 |
---|---|
[JPA] 값 타입 (0) | 2022.07.20 |
[Java] Map안에 Map 안에 List 만들기 (0) | 2022.07.19 |
[JPA] 프록시와 연관관계 관리 (0) | 2022.07.19 |
[JPA] 고급 매핑 (0) | 2022.07.18 |