스프링과 데이터베이스 액세스
- 스프링의 데이터베이스 액세스 작업은 jdbc 연동, ibatis/mybatis 연동, JPA/hibernate 연동 등 다양한 데이터베이스 액세스 기술과 연동해서 데이터베이스 액세스 작업을 구현할 수 있다.
- 스프링의 데이터베이스 액세스 작업 특징
- 다양한 데이터베이스 액세스 라이브러리와의 연동을 지원한다.
(jdbc, ibatis/mybatis, JPA/hibernate 등) - 일관된 데이터베이스 액세스 예외처리를 지원한다.
- 모든 데이터베이스 액세스 오류에 대해서 DataAccessException 예외를 발생시킨다.
- DataAccessException 클래스는 RuntimeException의 하위클래스여서 예외처리를 강제하지 않는다.
- 데이터베이스의 종류와 상관없이 오류 상황에 맞는 적절한 예외 객체를 발생시킨다.
- 예외 클래스의 이름도 예외상황에 맞는 이름이기 때문에 오류 상황을 더 쉽게 파악할 수 있다.
- 데이터베이스와 연결을 유지하는 Connection 객체는 Connecton Pool을 이용해서 획득하고, 사용 후 반납한다.
- Connection 객체는 데이터베이스와 미리 연결되어 있다.
- Connection Pool은 데이터베이스와 연결을 유지하는 Connection 객체를 관리하는 객체다.
- Connection Pool 객체를 스프링 컨테이너가 생성하게 하거나, 생성된 Connection Pool을 스프링 컨테이너에 등록한다.
- 선언적 트랜잭션 처리를 지원한다.
- 프로그램 코딩없이 간단한 설정만으로 트랜잭션처리(커밋,롤백) 기능을 지원받을 수 있다.
- 프로그램 코딩없이 간단한 설정만으로 트랜잭션처리(커밋,롤백) 기능을 지원받을 수 있다.
- 다양한 데이터베이스 액세스 라이브러리와의 연동을 지원한다.
spring-jdbc를 이용한 데이터베이스 액세스
(얘는 원래 안쓰는데 관계를 보여주기 위한 예시)
* spring-jdbc는 데이터베이스 액세스를 지원하는 JdbcTemplate 객체를 제공한다.
* JdbcTemplate는 spring-jdbc의 핵심 객체다.
* JdbcTemplate는 INSERT, UPDATE, DELETE, SELECT를 실행하는 메소드를 제공한다.
* 사용자 정의 DAO 클래스는 JdbcTemplate 객체를 의존성 주입받아서 데이터베이스 액세스 작업을 수행한다.
1. 필요한 라이브러리 의존성 추가 (pom.xml)
- jdbc 드라이버 라이브러리 의존성 추가
- sping-jdbc 라이브러리 의존성 추가
- pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.sample</groupId>
<artifactId>spring-jdbc</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- pom.xml 파일에서 사용되는 프로퍼티값(상수값)을 설정한다. -->
<properties>
<!-- 프로젝트의 자바버전을 정의한다. -->
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<!-- 로그출력을 지원하는 slf4j 라이브러리의 버전 정보를 상수로 정의한다. <version>${slf4j.version}</version>와
같이 ${} 형식으로 값을 사용할 수 있다. -->
<slf4j.version>1.7.25</slf4j.version>
</properties>
<!-- 프로젝트의 의존성 라이브러리를 정의한다. -->
<dependencies>
<!-- 오라클 데이터베이스 연동을 지원하는 jdbc 드라이버 라이브러리 의존성 추가 -->
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc11</artifactId>
<version>21.8.0.0</version>
</dependency>
<!-- spring-jdbc 라이브러리 의존성 정의
* spring-jdbc 라이브러리 의존성의 spring-jdbc, spring-tx 라이브러리 의존성도 포함한다.
* jdbc 기반의 데이터베이스 액세스 작업을 쉽게 구현하도록 지원하는 라이브러리다.
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.24</version>
</dependency>
<!-- spring-context 라이브러리 의존성 정의
spring-context 라이브러리 의존성은 spring-core, spring-beans, spring-aop, spring-expression 라이브러리도 포함한다.
* 스프링을 이용해서 객체 생성, 의존성 주입, 관점지향 프로그래밍 실습이 가능하다. -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.24</version>
</dependency>
<!-- 로그 출력을 지원하는 라이브러리 의존성 정의 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
</dependencies>
</project>
2. 스프링 컨테이너의 bean 설정 파일에 Connection Pool 객체 등록하기 (필수)
- db.properties (데이터베이스 연결 정보 설정)
- context.xml
3. spring-jdbc 라이브러리가 지원하는 JdbcTemplate 객체를 스프링 컨테이너에 등록하기
- context.xml
4. DAO 클래스와 Service 클래스를 스캔에서 스프링 컨테이너가 객체 생성하고, 의존하는 객체를 자동 의존성 주입시키기
- context.xml
5. 데이터베이스 엑세스 작업을 구현하는 DAO에 JdbcTemplate 객체를 의존성 주입받을 수 있도록 구현하기
- UserDao
6. 핵심 업무로직을 구현하는 Service에 DAO 객체를 의존성 주입받을 수 있도록 구현하기
* service는 핵심기능을 구현하기 위해 dao 주입 필요
dao는 데이터베이스 액세스를 해야 하니까 jdbcTemplate 주입 필요
* mybitis 참고링크
https://mybatis.org/mybatis-3/ko/index.html
mybatis
- SQL Mapping Framework
- SQL 실행에 필요한 정보를 포함하고 있는 객체
- SQL 실행 결과를 저장하는 객체를 SQL과 매핑하면 해당 SQL를 실행시키고, 결과값을 반환하는 프레임워크
- ibatis의 후속 버전
- ibatis와 많은 부분이 유사함
mybatis의 주요 구성요소
- Mapper 인터페이스
- 데이터베이스 액세스 작업이 정의된 인터페이스
- 개발자가 작성 (구현객체를 mybatis에서 알아서 만들어줌)
- 예시
- Mapper 파일
- SQL과 객체 매핑 정보가 정의된 XML 파일이다. (테이블당 1개씩 작성)
- Mapper 인터페이스의 전체이름을 namespace로 설정한다.
- 개발자가 작성
- ibatis와 mybatis
- parameterClass, resultClass -> parameterType, resultType
- #파라미터명# -> #{파라미터명}
- dynamic 쿼리에서 <if>, <choose>, <when>, <otherwise>, <foreach> 태그를 사용해서 조건식처리, 반복처리 가능하다.
- dynamic 쿼리에서 <where>, <set> 태그를 사용해서 불필요한 and와 ,를 제거할 수 있다. - 예시
- Mapper 인스턴스 (인터페이스 구현객체)
- Mapper 인터페이스를 구현한 객체다.
- 개발자가 구현하지 않는다.
- mybatis와 mybatis-spring 라이브러리에서 Mapper 인터페이스를 구현한 객체를 자동으로 생성하고, 스프링 컨테이너의 빈으로 등록시킨다.
(그러기 위해서 해야할 일 : Mapper 인터페이스와 Mapper 파일의 namespace 일치시키기)
-> Mapper 인터페이스의 메소드를 재정의 함
- mybatis 매퍼파일의 <where> 태그
==================================================================
<where> 태그를 사용하지 않는 경우
==================================================================
select
*
from
web_products
where
<if test="deleted != null">
product_deleted = #{deleted}
</if>
<if test="minPrice > 0">
and product_price >= #{minPrice}
</if>
<if test="maxPrice > 0">
and product_price <= #{maxPrice}
</if>
<if test="categoryNo != null">
and product_category_no = #{categoryNo}
</if>
--------------------------------------------------------
Map<String, Object> param = new HashMap<>();
param.put("deleted", 'N');
param.put("minPrice", 10000);
select
*
from
web_products
where
product_deleted = #{deleted}
and product_price >= #{minPrice}
--------------------------------------------------------
Map<String, Object> param = new HashMap<>();
select
*
from
web_products
where -- 문법 오류가 발생한다. (map에 아무것도 안담겨서 where만 남음)
--------------------------------------------------------
Map<String, Object> param = new HashMap<>();
param.put("minPrice", 10000);
param.put("maxPrice", 50000);
select
*
from
web_products
where
and product_price >= #{minPrice} -- 문법 오류가 발생한다. (deleted가 null이라서 and부터 시작)
and product_price <= #{maxPrice}
--------------------------------------------------------
==================================================================
<where> 태그를 사용하는 경우
==================================================================
select
*
from
web_products
<where>
<if test="deleted != null">
product_deleted = #{deleted}
</if>
<if test="minPrice > 0">
and product_price >= #{minPrice}
</if>
<if test="maxPrice > 0">
and product_price <= #{maxPrice}
</if>
<if test="categoryNo != null">
and product_category_no = #{categoryNo}
</if>
</where>
--------------------------------------------------------
Map<String, Object> param = new HashMap<>();
param.put("deleted", 'N');
param.put("minPrice", 10000);
select
*
from
web_products
where
product_deleted = #{deleted}
and product_price >= #{minPrice}
* <where>과 </where>사이에 동적으로 추가되는 조건이 하나라도 있으면
where 키워드가 추가된다.
--------------------------------------------------------
Map<String, Object> param = new HashMap<>();
select
*
from
web_products
* <where>과 </where>사이에 동적으로 추가되는 조건이 하나도 없으면
where 키워드는 추가되지 않는다.
--------------------------------------------------------
Map<String, Object> param = new HashMap<>();
param.put("minPrice", 10000);
param.put("maxPrice", 50000);
select
*
from
web_products
where
product_price >= #{minPrice}
and product_price <= #{maxPrice}
* <where>과 </where>사이에 동적으로 추가되는 조건이 있고,
첫번째 조건에 and 키워드가 있으면, and를 제거한다.
--------------------------------------------------------
mybatis의 주요 API
* 개발자가 직접 mybatis의 주요 API를 사용해서 코딩하는 경우는 절대 없다.
- SqlSessionFactoryBuilder
- mybatis 환경설정 파일을 읽어서 SqlSessionFactory 객체를 생성한다
- SqlSessionFactory
- SqlSession 객체를 제공한다.
- 애플리케이션이 실행되는 동안 싱글턴 객체로 관리되어야 한다.
- 주요 메소드
SqlSession openSession() : 새로운 SqlSession 객체를 반환한다.
- SqlSession
- SQL을 실행하는 메소드를 제공하는 객체
- Sql을 실행할 때마다 SqlSessionFactory의 openSession() 메소드를 실행해서 새로운 SqlSession 객체를 획득해서 사용하고, Sql 실행이 완료되면 close() 메소드를 호출해서 폐기한다.
- 주요 메소드
<T> T selectOne(String id, Object parameter)
: 결과값이 하나 조회되는 SELECT 문을 실행시키고, 값을 반환한다.
<E> List<E> selectList(String id, Object parameter)
: 결과값이 여러개 조회되는 SELECT 문을 실행시키고, 값을 반환한다.
int insert(String id, Object parameter)
: INSERT 문을 실행시키고, 추가된 행의 개수를 반환한다.
int update(String id, Object parameter)
: UPDATE 문을 실행시키고, 변경된 행의 개수를 반환한다.
int delete(String id, Object parameter)
: DELETE 문을 실행시키고, 삭제된 행의 개수를 반환한다.
void commit()
: INSERT, UPDATE, DELETE 문의 실행결과를 테이블에 영구적으로 반영시킨다.
void rollback()
: INSERT, UPDATE, DELETE 문의 실행의 테이블 반영을 취소시킨다.
void close()
: SqlSession 객체를 폐기한다.
<T> T getMapper(Class<T> type)
: type에서 지정한 Mapper 인터페이스를 구현한 Mapper 인스턴스를 반환한다.
예시)
Mapper 인터페이스 정의
public interface UserMapper {
void insertUser(User user)
}
Mapper 파일 정의
<mapper namespace="com.sample.mapper.UserMapper">
<insert id="insertUser" parameterType="com.sample.vo.User">
insert into web_users (user_id, user_password, user_name, user_email)
values (#{id}, #{password}, #{name}, #{email})
</insert>
</mapper>
Mapper 인스턴스 획득하기
SqlSession session = sqlSessionFactory.openSession();
UserMapper instance = session.getMapper(UserMapper.class);
* instance변수에는 UserMapper 인터페이스를 구현한 객체가 대입된다.
* mybatis-spring 라이브러리는 모든 Mapper인터페이스를 스캔해서 Mapper 인스턴스를 생성하고, 스프링 컨테이너의 빈으로 등록시킨다
'수업내용 > Spring' 카테고리의 다른 글
[2023.1.4.수] 스프링 MVC 웹 애플리케이션 1 (준비, 환경설정) (0) | 2023.01.04 |
---|---|
[2023.1.3.화] mybatis로 데이터베이스 액세스, 다이나믹 쿼리 (0) | 2023.01.03 |
[2022.12.30.금] 스프링의 의존성 주입 (0) | 2022.12.30 |
[2022.12.29.목] 스프링 DI(의존성주입), AOP(관점지향), Maven (0) | 2022.12.29 |
[2022.12.28.수] model2로 할 일(Todo) 실습 (0) | 2022.12.29 |