mybatis로 데이터베이스 액세스 하기
0. mybatis 프로젝트 생성
new -> project -> maven project



1. 필요한 라이브러리 의존성 추가
*spring-mybatis/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-mybatis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<slf4j.version>1.7.25</slf4j.version>
</properties>
<dependencies>
<!--
스프링 컨테이너를 제공하는 라이브러리 의존성 추가
* 스프링 컨테이너는 객체 생성, 의존성 주입, 관점지향 프로그램을 지원한다.
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.24</version>
</dependency>
<!--
데이터베이스 액세스를 지원하는 라이브러리 의존성 추가
* 일관된 예외처리, 선언적 트랜잭션처리를 지원한다.
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.24</version>
</dependency>
<!--
mybatis 라이브러리 의존성 추가
* mybatis는 SQL Mapper 프레임워크다. ibatis보다 더 쉬운 데이터베이스 액세스를 구현할 수 있다.
-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>
<!--
mybatis-spring 라이브러리 의존성 추가
* mybatis와 spring의 연동을 지원한다.
* mybatis를 이용하는 데이터베이스 액세스 작업의 핵심 객체를 스프링의 빈으로 등록시킨다.
-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc11</artifactId>
<version>21.8.0.0</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 객체 등록하기 (필수)
- context.xml 생성


* context.xml
<!--
db.properties 파일 정보를 관리하는 객체를 스프링 컨테이너의 빈으로 등록하기
-->
<context:property-placeholder location="classpath:spring/db.properties"/>
<!--
Connection객체를 관리하는 Connection Pool 객체를 스프링컨테이너의 빈으로 등록하기
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${db.driver-class-name}"></property>
<property name="url" value="${db.url}"></property>
<property name="username" value="${db.username}"></property>
<property name="password" value="${db.password}"></property>
</bean>

3. Mapper 인터페이스와 Mapper 파일을 작성하기
* Mapper 인터페이스 작성

* UserMapper에 대고 copy qualified name 한 뒤, 매퍼파일 (users.xml)의 namespace에 붙여넣기

- 매퍼파일 생성 (users.xml)


* UserMapper 인터페이스와 짝이 되는 Mapper파일 (users.xml) 작성
( -> UserMapper가 데이터베이스와 액세스 하게 됨)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<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>
<update id="updateUser" parameterType="com.sample.vo.User">
update
web_users
set
user_password = #{password},
user_enabled = #{enabled},
user_updated_date = sysdate
where
user_id = #{id}
</update>
<select id="getUsers" resultType="com.sample.vo.User">
select
user_id as id,
user_password as password,
user_name as name,
user_email as email,
user_enabled as enabled,
user_updated_date as updatedDate,
user_created_date as createdDate
from
web_users
<where>
<if test="enabled != null">
user_enabled = #{enabled}
</if>
</where>
order by
user_created_date desc
</select>
<select id="getUserById" parameterType="string" resultType="com.sample.vo.User">
select
user_id as id,
user_password as password,
user_name as name,
user_email as email,
user_enabled as enabled,
user_updated_date as updatedDate,
user_created_date as createdDate
from
web_users
where
user_id = #{value}
</select>
<select id="getUserByEmail" parameterType="string" resultType="com.sample.vo.User">
select
user_id as id,
user_password as password,
user_name as name,
user_email as email,
user_enabled as enabled,
user_updated_date as updatedDate,
user_created_date as createdDate
from
web_users
where
user_email = #{value}
</select>
</mapper>
4. mybatis-config.xml에 mybatis 환경설정 파일을 작성하기
- mapperConfiguration 파일 생성


5. 스프링 컨테이너의 빈 설정파일에 SqlSessionFactory 객체(mybatis 핵심객체) 등록하기
- SqlSessionFactoryBean 객체는 의존성 주입으로 전달받은 dataSource, configLocation, mapperLocation, typeAliasespackage 등의 값을 이용해서 SqlSessionFactory 객체를 생성하고, 스프링 컨테이너에 등록시킨다.
- SqlSessionFactory는 new 해서 만들어지는 객체가 아니라서 이런식으로 정보를 전달받아서 객체가 생성됨
- dataSource는 mybatis가 데이터베이스 액세스할 때 데이터베이스와 연결된 Connection 객체를 제공하는 Connection Pool 객체를 의존성 주입받는다.
- configLocation은 mybatis 환경설정 파일의 경로 및 이름을 의존성 주입받는다.
- mapperLocations는 mybatis의 SQL 매퍼파일의 경로 및 이름을 의존성 주입받는다. ( *.xml -> 모든 xml 파일 )
- typeAliasesPackage는 SQL 매퍼파일에서 parameterType과 resultType으로 사용되는 vo, dto 클래스가 정의된 패키지명을 의존성 주입받는다. ( 이 vo, dto에 있는 객체들을 parameterTyper, resultType으로 쓸거야 )
- SqlSessionFactory는 애플리케이션이 실행되는 싱글턴 객체로 관리되어야 한다. (스프링 컨테이너는 객체를 싱글턴 객체로 관리한다.)
- SqlSession 객체는 INSERT, UPDATE, DELETE, SELECT 쿼리문을 실행시키는 메소드, 커밋/롤백을 실행시키는 메소드, Mapper 인터페이스를 구현한 Mapper 인스턴스를 반환하는 메소드를 가지고 있는 객체다.
- context.xml

6. 스프링 컨테이너의 빈 설정파일에 MapperScannerConfigure 객체 등록하기
- interface UserMapper, interface PostMapper, interface CommentMapper 등의 Mapper 인터페이스와 Mapper 파일이 각각 정의되어 있다면, MapperScannerConfigure객체가 그걸 스캔해서
UserMapper의 구현객체(인스턴스), PostMapper의 구현객체(인스턴스), CommentMapper의 구현객체(인스턴스)를 생성한다.
각각의 구현객체에서는 메소드 이름과 일치하는 SQL 구문을 실행시키는 코드가 생성되어 있다.
-> 실제로 얘가 가장 필요함 (db액세스 하는 메소드가 구현되어 있기 때문) - base-package : Mapper 인터페이스들이 어디에 있는지 알려주는 것
- factory-ref : sqlSessionFactory 를 의존성 주입받음
- MapperScannerConfigure -> SqlSessionFactory가 제공하는 SqlSession 객체를 이용해서 -> Mapper 인스턴스 생성
( Mapper 파일들을 스캔해서 )
- context.xml

7. 스프링 컨테이너의 빈 설정파일에 UserService 객체 등록하기
<context:annotation-config />
// 의존성 주입
<context:component-scan base-package="com.sample.service" />
// 패키지에서 객체 생성하고 스프링 빈에 등록
궁극적으로는 UserMapper 구현객체, UserService 객체를 가지고 싶었던 것

* 모두 합쳐진 context.xml 최종
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!--
db.properties 파일 정보를 관리하는 객체를 스프링 컨테이너의 빈으로 등록하기
-->
<context:property-placeholder location="classpath:spring/db.properties"/>
<!--
Connection객체를 관리하는 Connection Pool 객체를 스프링컨테이너의 빈으로 등록하기
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${db.driver-class-name}"></property>
<property name="url" value="${db.url}"></property>
<property name="username" value="${db.username}"></property>
<property name="password" value="${db.password}"></property>
</bean>
<!--
SqlSessionFactory 객체를 스프링 컨테이너의 빈으로 등록하기
* SqlSessionFactory는 mybatis의 핵심객체다.
* SqlSessionFactory는 SqlSession 객체를 제공하는 객체다.
* SqlSession 객체는 Mapper 인터페이스를 구현한 Mapper 인스턴스를 생성하는 객체다.
* 아래의 MapperScannerConfigure는 SqlSession 객체를 이용해서 Mapper 인스턴스를 생성한다.
(-> Session 객체를 이용해서 Mapper 인스턴스를 생성하려면 SessionFactory가 있어야 함)
* SqlSessionFactoryBean은 mybatis 환경설정파일, 매퍼파일, Connection Pool을 주입받아서 이 정보를 가지고
SqlSessionFactory 객체를 생성하고, 생성된 SqlSessionFactory 객체를 스프링 컨테이너의 빈으로 등록시킨다.
* 클래스이름이 -FactoryBean으로 끝나는 경우,
<bean class="-FactoryBean"></bean> 이와 같이 설정하면
-FactoryBean 객체가 스프링 컨테이너의 빈으로 등록되는 것이 아니라
-FactoryBean의 getObject() 메소드가 반환하는 객체가 스프링 컨테이너의 빈으로 등록된다.
-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="mybatis/mybatis-config.xml"></property>
<property name="mapperLocations" value="classpath:mybatis/mappers/*.xml"></property>
<property name="typeAliasesPackage" value="com.sample.vo"></property>
</bean>
<!--
<mybatis-spring:scan />
* MapperScannerConfigure 객체를 스프링 컨테이너의 빈으로 등록한다.
* MapperScannerConfigure 객체는 base-package 속성으로 지정된 패키지에서
Mapper 인터페이스를 전부 스캔해서 Mapper 인터페이스를 구현한 Mapper 인스턴스(객체)를 생성하고,
생성된 Mapper 인스턴스를 스프링 컨테이너의 빈으로 등록시킨다.
-->
<mybatis-spring:scan base-package="com.sample.mapper" factory-ref="sqlSessionFactory"/>
<!-- 의존성 주입 -->
<context:annotation-config />
<!-- 패키지에서 스캔해서 객체 생성, 스프링 빈에 등록 -->
<context:component-scan base-package="com.sample.service" />
</beans>
* UserService

* App



* Post 객체 (@Alias("Post") 추가)

* PostMapper 인터페이스

@Param : 원래는 SqlMapper.SelectOne("posts.getPosts", post) 이런식으로 값을 하나만 넘길 수 있었는데,
@Param을 이용하면 여러개를 보낼 수 있음
"id"로 찾으면 String userId가 찾아짐
* context.xml

typeAliase ~ -> 저 경로 vo에 있는 객체들을 parameterType, resultType으로 쓸거야
* 매퍼파일 post.xml
<foreach>, <where>, <if>, <choose> 사용법 보기!!!!
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sample.mapper.PostMapper">
<!--
void deletePosts(@Param("numbers") List<Integer> numbers);
* Mapper 인터페이스에 @Param 어노테이션으로 parameter가 지정되어 있기 때문에
SQL 매핑 시 parameterType을 생략할 수 있다.
-->
<delete id="deletePosts">
delete from
web_posts
where
post_no in
<foreach collection="numbers" item="num" open="(" close=")" separator=",">
#{num}
</foreach>
</delete>
<select id="getPosts" parameterType="map" resultType="Post" >
select
post_no as no,
post_title as title,
post_user_id as userId,
post_content as content,
post_read_count as readCount,
post_comment_count as commentCount,
post_deleted as deleted,
post_updated_date as updatedDate,
post_created_date as createdDate
from
web_posts
<where>
<if test="deleted != null">
post_deleted = #{deleted}
</if>
<if test="userId != null">
and post_user_id = #{userId}
</if>
<choose>
<when test="opt == 'title'">
and post_title like '%' || #{keyword} || '%'
</when>
<when test="opt == 'writer'">
and post_user_id in (select
user_id
from
web_users
where
user_name = #{keyword})
</when>
<when test="opt == 'content'">
and post_content like '%' || #{keyword} || '%'
</when>
</choose>
</where>
</select>
</mapper>
- deleted에 'N' 값을 넣으면 -> where문 실행,
값을 넣지 않으면 null -> where문 실행 x

* PostService
package com.sample.service;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.sample.mapper.PostMapper;
import com.sample.vo.Post;
@Service
public class PostService {
@Autowired
private PostMapper postMapper;
// 검색하기
public List<Post> searchPosts(Map<String, Object> param){
return (List<Post>) postMapper.getPosts(param);
}
// 선택 삭제하기
public void deleteSelectedPosts(List<Integer> numbers) {
postMapper.deletePosts(numbers);
}
}

* App




@Param, <forEach> 태그 활용

여러 개를 선택해서 삭제한다고 할 때 , ?, ?, ? 로 넘기는데
근데 몇개가 될지 몰라 -> 가변적일 때
@Param으로 넘기고 <forEach>로 받음

'수업내용 > Spring' 카테고리의 다른 글
| [2023.1.5.목] 스프링 MVC 웹 애플리케이션 2 (조립, 회원가입, 예외처리) (0) | 2023.01.05 |
|---|---|
| [2023.1.4.수] 스프링 MVC 웹 애플리케이션 1 (준비, 환경설정) (0) | 2023.01.04 |
| [2023.1.2.월] jdbc, mybatis를 이용한 스프링 데이터베이스 액세스 (0) | 2023.01.02 |
| [2022.12.30.금] 스프링의 의존성 주입 (0) | 2022.12.30 |
| [2022.12.29.목] 스프링 DI(의존성주입), AOP(관점지향), Maven (0) | 2022.12.29 |