웹/TIL

0421 MyBatis / MyBatis-Spring

행복한 개복치 2022. 4. 22. 16:48

<MyBatis>
- MyBatis를 이용하면 DaoImpl에서 하나씩 직접 작성하던 쿼리문을 간단하게 처리할 수 있음.

 

<MyBatis 사용을 위한 설정>
1. pom.xml에 mybatis dependency 추가하기
2. scr/main/resources/에 mybatis-config.xml 생성
 - envirionments(DB 정보) 와 mappers 는 필수

<?xml version="1.0" encoding="UTF-8" ?>
<!-- mybatis 사용 규약 / dtd에 나와있는 순서대로 xml을 작성해야함 -->
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

<!-- DB 정보를 담은 문서 -->
<!-- 이를 생성하기 싫다면 아래 el 표기문에 직접 입력해도 됨 -->
	<properties resource="dbinfo.properties"/>

<!-- type에 있는 object에 대한 alias(별칭) 등록 -->
	<typeAliases>
		<typeAlias type="com.ssafy.guestbook.model.GuestBookDto" alias="guestbook" />
		<typeAlias type="com.ssafy.guestbook.model.MemberDto" alias="member" />
		<typeAlias type="com.ssafy.guestbook.model.FileInfoDto" alias="fileinfo" />
	</typeAliases>
	
	<environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${dbid}"/>
                <property name="password" value="${dbpwd}"/>
            </dataSource>
        </environment>
    </environments>
    
<!--     쿼리문을 작성해준 문서들 -->
     <mappers>
		<mapper resource="guestbook.xml" />
		<mapper resource="member.xml" />
	</mappers>
	
</configuration>​


3. 해당 mapper 작성

ex) member.xml

<?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">

<!-- 보통 필요한 Dao가 있는 위치를 namespace로 지정 -->
<mapper namespace="com.ssafy.guestbook.model.dao.MemberDao">

<!-- 	id는 dao에 있는 메서드 이름과 동일하게 / parameterType은 어디에서 값을 가져올건지 -->
	<insert id="registerMember" parameterType="member">
	insert into ssafy_member (userId, userName, userPwd, email, joinDate)
<!-- 	MemberDto에 있는 property 이름과 동일하게 해줘야 자동으로 값이 들어감 -->
	values(#{userId}, #{userName}, #{userPwd}, #{email}, now())
	</insert>

<!-- 	resultType은 어떤걸 반환할건지 -->
<!-- 	java 내장객체들은 소문자로만 적어줘도 자동매핑됨 (map <- java.util.Map)-->
	<select id="login" parameterType="map" resultType="member">
	select username, userid, email
	from ssafy_member
	where userid = #{userId} and userpwd = #{userPwd}
	</select>
</mapper>


4. DBUtil.java에서 사용하던 Connection 대신 SqlSessionFactory 사용
- 다른곳에서 SqlSession 사용시 getter를 이용해서 얻어오도록


5. DaoImpl에서 SqlSession을 이용해 db에 접근
- try resource문으로 SqlSession 관리

ex) MemberDaoImpl.java

package com.ssafy.guestbook.model.dao;

import java.sql.SQLException;
import java.util.Map;

import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Repository;

import com.ssafy.guestbook.model.MemberDto;
import com.ssafy.util.SqlMapConfig;

@Repository
public class MemberDaoImpl implements MemberDao {

//	항상 같은 주소로 접근하니까 상수로 작성해둠
	private final String NAMESPACE = "com.ssafy.guestbook.model.dao.MemberDao.";

	@Override
	public int idCheck(String id) throws SQLException {
		return 0;
	}

	@Override
	public void registerMember(MemberDto memberDto) throws SQLException {
		try (SqlSession sqlSession = SqlMapConfig.getSqlSession()) {
//			mapper(member.xml)에 있는 id 호출, 정보를 갖고있는 객체
			sqlSession.insert(NAMESPACE + "registerMember", memberDto);
//			mybatis는 자동커밋이 기본이 아님
			sqlSession.commit();
		}
	}

	@Override
	public MemberDto login(Map<String, String> map) throws SQLException {
		try (SqlSession sqlSession = SqlMapConfig.getSqlSession()) {
//			객체 하나만 받아옴(로그인하면 사용자 한명의 정보만 필요하므로)
			return sqlSession.selectOne(NAMESPACE + "login", map);
		}
	}

}



<Mybatis-Spring>
Spring에서 mapper 객체관리를 할 수 있도록 해줌
- SqlMapConfig.java 와 mybatis-config.xml 역할을 root-context.xml(비웹부분)에서 대신 해줌
- DaoImpl이 사라지고 mapper(Dao) 인터페이스만 남음

 

<변경된 부분>

1. root-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:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans https://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
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
	
	<!-- Root Context: defines shared resources visible to all other web components -->
		
	<context:component-scan base-package="com.ssafy.guestbook.model, com.ssafy.guestbook.aop" />
	
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
	
	<!-- <bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
		<property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
		<property name="url" value="jdbc:mysql://127.0.0.1:3306/ssafyweb?serverTimezone=UTC&amp;useUniCode=yes&amp;characterEncoding=UTF-8"/>
		<property name="username" value="ssafy"/>
		<property name="password" value="ssafy"/>
	</bean> -->
	
	<bean id="ds" class="org.springframework.jndi.JndiObjectFactoryBean">
		<property name="jndiName" value="java:comp/env/jdbc/ssafy"></property>
	</bean>
	
<!-- 	mybatis-config.xml 대체 -->
	<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="ds"></property>
		<property name="mapperLocations" value="classpath:mapper/*.xml"></property>
<!-- 		<property name="configLocation" value="classpath:mybatis-config.xml"></property> -->
<!-- 		아래처럼 지정할 경우, alias 이름이 클래스의 이름으로 설정됨 -->
		<property name="typeAliasesPackage" value="com.ssafy.guestbook.model"></property>
	</bean>
	
<!-- 	SqlSession -->
	<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!-- 		SST의 디폴트 생성자가 없기때문에 생성자 설정을 해줘야함 -->
		<constructor-arg ref="sqlSessionFactoryBean"></constructor-arg>
	</bean>
	
<!-- 	트랜잭션 관리  객체 생성-->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="ds"></property>
	</bean>
	
<!-- 	어노테이션(transactional)으로 관리 가능하도록 -->
	<tx:annotation-driven transaction-manager="transactionManager"/>
		
</beans>

 

2. ServiceImpl.java

ex) MemberServiceImpl.java

package com.ssafy.guestbook.model.service;

import java.util.Map;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.ssafy.guestbook.model.MemberDto;
import com.ssafy.guestbook.model.mapper.MemberMapper;

@Service
public class MemberServiceImpl implements MemberService {

	@Autowired
	private SqlSession sqlSession;

	@Override
	public int idCheck(String id) throws Exception {
		return 0;
	}

	@Override
	public void registerMember(MemberDto memberDto) throws Exception {
//		root-context.xml에서 SqlSession 설정을 해줬기때문에 mapper class(이전 DaoImpl)만 지정하면 알아서 쿼리문과 연결
		sqlSession.getMapper(MemberMapper.class).registerMember(memberDto);

	}

	@Override
	public MemberDto login(Map<String, String> map) throws Exception {
		return sqlSession.getMapper(MemberMapper.class).login(map);
	}

}

+ 트랜잭션이 발생하는 메서드에 @Transactional 어노테이션을 해놓으면

error가 없을때 자동으로 커밋, error 발생 시 자동 롤백이 됨