MyBatis

4.Java 에노테이션으로 MyBatis 연동 및 테스트

Jungsoomin :) 2020. 7. 13. 23:45

금일 남는 시간동안 열심히 자바 에노테이션으로 MyBatis연동을 해보았는데, 기억도 되살리고 자바로 처음 연동해보고 굉장히  감회가 새롭다. :)

 

package com.soomin.dto;

import java.sql.SQLException;
import java.util.List;

import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.soomin.vo.MemberVO;

@Mapper
@Component
@Transactional(rollbackFor = SQLException.class)
public interface MemberDAO {
	List<MemberVO> selectMember() throws Exception;
}

DAO클래스는 Mapper에노테이션으로 스캔한다. xml파일로 맵핑하거나 구현하는게 아닌 에노테이션으로 Mapper를 정의한다는게 신기하다.

 

MyBatis에서 제공하는 mybatis-spring 모듈을 이용하면,  @Mapper 인터페이스를 스프링 빈으로 주입받아 사용할 수 있다고한다.

 

@Select @Insert @Delete로 지정까지 가능하다니 여간 편해보이는게 아니다...

 

@Component 에노테이션이 없어도 되는게 아닐까 싶은데, 나중에 다시 한번 테스트 해봐야겠다 싶다.

 


설정 클래스를 연결해주는 클래스이다. 나누어져 있는 모든 설정클래스들을 모아주고 싶었다.

 

package com.soomin.init;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import({MvcConfiguration.class,TransactionConfiguration.class, SQLConfiguration.class})
public class ContextConfiguration {
}

 


ApplicationContext의 getResource 메서드로 클래스 패스를 잡아주는 과정이다. 

핵심 객체인 SqlSessionFactoryBeanSqlSessionTemplate을 빈으로 등록해 놓았다.

퍼시스턴스 레이어 라고 생각해서 @MapperScan으로 패키지를 잡아주었다.

package com.soomin.init;

import java.io.IOException;

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan(basePackages = {"com.soomin.dto"})
public class SQLConfiguration {
	@Autowired
	ApplicationContext applicationContext;
	
	@Bean
	public SqlSessionFactoryBean factoryBean(DataSource dataSource) throws Exception {
		 SqlSessionFactoryBean SqlFactory = new SqlSessionFactoryBean();
		 SqlFactory.setDataSource(dataSource);
		 SqlFactory.setConfigLocation(applicationContext.getResource("classpath:/mybatis/mybatis-config.xml"));
		 SqlFactory.setMapperLocations(applicationContext.getResources("classpath:/mybatis/mappers/*Mapper.xml"));
		 return SqlFactory;		 
	}
	
	@Bean
	public SqlSessionTemplate sqlSession(SqlSessionFactory sqlSessionFactory) {
		return new SqlSessionTemplate(sqlSessionFactory);
	}
	
}

DB 연동을 위한 트랜젝션 메니저 설정이다. 이제보니 dto클래스를 또 @ComponentScan 해놨구나..

        반드시! 기억해야할 점은 "jdbc:mysql://127.0.0.1:3306/spring5fs?serverTimezone=UTC&useSSL=false&characterEncoding=utf8" 처럼 각 설정 정의 이다.에서 xml 파일에 정의한다면 &amp; 를 넣고 자바클래스로 정의한다면 &로 마무리한다는 것이다!

package com.soomin.init;

import javax.sql.DataSource;

import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages = {"com.soomin.dto"})
public class TransactionConfiguration {
	
	@Bean(destroyMethod = "close")
	public DataSource dataSource() {
		BasicDataSource dataSource = new BasicDataSource();
		dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
		dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/spring5fs?serverTimezone=UTC&useSSL=false&characterEncoding=utf8");
//		dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/spring5fs?serverTimezone=UTC&amp;useSSL=false&amp;characterEncoding=utf8");
		dataSource.setUsername("spring5");
		dataSource.setPassword("spring5");
		return dataSource;
	}

	@Bean
	public PlatformTransactionManager transcationManager() {
		return new DataSourceTransactionManager(dataSource());
	}
}

Resource폴더에 있는 log4j.xml파일이다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

	<!-- Appenders -->
	<appender name="console" class="org.apache.log4j.ConsoleAppender">
		<param name="Target" value="System.out" />
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="%-5p: %c - %m%n" />
		</layout>
	</appender>
	
	<!-- Application Loggers -->
	<logger name="com.soomin.controller">
		<level value="info" />
	</logger>
	
	<!-- 3rdparty Loggers -->
	<logger name="org.springframework.core">
		<level value="info" />
	</logger>
	
	<logger name="org.springframework.beans">
		<level value="info" />
	</logger>
	
	<logger name="org.springframework.context">
		<level value="info" />
	</logger>

	<logger name="org.springframework.web">
		<level value="info" />
	</logger>

	<!-- Root Logger -->
	<root>
		<priority value="info" />
		<appender-ref ref="console" />
	</root>
	
</log4j:configuration>

Resource 폴더의

log4jdbc.log4j2.properties 파일이다. 로그출력을 위해 설정해놓았다.

log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator

slf4j 의 징검다리로 구현체인 log4jdbc.log4j2를 만들었으니, logback.xml 파일을 생성하여 정의했다.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/base.xml"/>
    
    <!-- log4jdbc-log4j2 -->
    <logger name="jdbc.sqlonly"     level="DEBUG" />
    <logger name="jdbc.sqltiming"     level="INFO" />
    <logger name="jdbc.audit"         level="WARN" />
    <logger name="jdbc.resultset"     level="ERROR" />
    <logger name="jdbc.resultsettable" level="ERROR" />
    <logger name="jdbc.connection"     level="INFO" />
 
</configuration>

Resource 폴더아래 mybatis 폴더에 있는 mybatis-config.xml이다. VO객체의 별칭지정을 해놓았다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration 
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
 	<typeAliases>
 		<typeAlias type="com.soomin.vo.MemberVO" alias="memberVO"/>
 	</typeAliases>
        
    </configuration>

그 밑에 있는 mappers 폴더의

Mapper.xml 파일이다, 큰 건없고..@Select 에노테이션 설정대신 xml파일로 정의해놓은 것 뿐이다.. 개인적으로 에노테이션으로 해보고싶다.

  
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 
<mapper namespace="com.soomin.dto.MemberDAO">
 	<resultMap type="memberVO" id="memberVOResult">
 		<result column="ID" property="id"/>
 		<result column="EMAIL" property="email"/>
 		<result column="PASSWORD" property="password"/>
 		<result column="NAME" property="name"/>
 		<result column="REGDATE" property="regdate" javaType="java.sql.Timestamp"/>
 	</resultMap>
 	
 	<select id="selectMember" resultType="memberVO" resultMap="memberVOResult">
 	SELECT * FROM MEMBER
 	</select>
    
</mapper>

대망의 JUnit을 이용한 테스트 이다!

   @Test 에노테이션은 각 테스트 메서드에 붙이게 된다.

   @RunWith 에노테이션에 속성 값으로 SpringJUnit4ClassRunner.class 를 주었는데  @RunWith에 Runner클래스를 설정하면 JUnit에 내장된 Runner대신 그 클래스를 실행한다는 뜻이다. 

  @ContextConfiguration 의 지정방법은 xml 파일 뿐인 줄 알았으나 classes 속성으로 스프링 설정클래스(@Configuration)을 찾아 해당 빈을 사용할 수 있다고 한다! 또 하나 배웠다..ㅠㅠ

  @WebAppConfiguration 에노테이션Test시  MVC 관련 모듈이 있을경우 톰캣에 의존성을 가지게 되기 때문에 선언하는 것이라고 한다.

package mybatistest;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

import com.soomin.dto.MemberDAO;
import com.soomin.vo.MemberVO;

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = {com.soomin.init.ContextConfiguration.class})
public class MyBatisTest {
	
	@Autowired
	private MemberDAO memberDao;
	
	@Autowired
	private SqlSessionFactory sqlSessionFactory;
	
	@Test
	public void SqlSessionFactoryTest() {
		System.out.println("\n sqlSessionFactoryBean >>>>>>> "+sqlSessionFactory);
	}
	@Test
	public void SqlSessionTest() {
		try(SqlSession sqlSession = sqlSessionFactory.openSession();){
			System.out.println("\n sqlSession >>>>>>> "+sqlSession);
		}catch(Exception e) {
			e.getStackTrace();
		}
	}
	@Test
	public void myBatisTest() throws Exception {
		System.out.println("\n >>>>>>>>MyBatis 구동");
		try {
		List<MemberVO> list =memberDao.selectMember();
		System.out.println();
		list.forEach(m -> {System.out.println(m.toString());});
		}catch(Exception e) {
			e.printStackTrace();
		}
		System.out.println("\n MemberDao의 selectMember() 실행완료");
		
	}
	
}

이상으로 금일 도전했던 MyBatis 자바 Config 설정을 마친다. 더 열심히 배우고 더 노력해서 훌륭한 개발자가 되려하고 더 좋은 방식더 깔끔한 방식으로 MyBatis루고 싶다!

 

자유자제로 다룰 수 있는 날이 언젠가 찾아오길 바란다..힘내야지..!

 

'MyBatis' 카테고리의 다른 글

log4j.xml  (0) 2020.07.18
Mybatis, 테이블 연동과 기본적인 DML 조작  (0) 2020.07.18
3.MyBatis를 이용한 데이터 조회와 연동-log  (0) 2020.07.11
0.Basic.개발의 주요 구조.  (0) 2020.07.11
2..Mybatis의Test  (0) 2020.07.11