블로그 이미지
윤영식
Full Stacker, Application Architecter, KnowHow Dispenser and Bike Rider

Publication

Category

Recent Post

2013. 11. 20. 09:11 My Projects/BI Dashboard

이전 블로그에서 myBatis를 사용하면서 DAO Interface를 만들고, DAO를 구현한 클래스를 사용하는 방법을 테스트해 보았다. DAO를 구현하지 않고 Interface의 메소드만 선언하면 myBatis에서 자동 구현되어 사용할 수 있게 하는 방법을 알아보자 




1. Mapper 인식하는 방식

  - Spring context xml에 설정하기 : UserMapper는 단순 Interface

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">

  <property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />

  <property name="sqlSessionFactory" ref="sqlSessionFactory" />

</bean>

  - Mapper scanner를 등록하는 방식 : component-scan과 유사하게 mapper를 검색해 준다 (안됨)

<beans xmlns="http://www.springframework.org/schema/beans"

  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"

  xsi:schemaLocation="

  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

  http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd">

 

  <mybatis:scan base-package="org.mybatis.spring.sample.mapper" />


</beans>

  - @MapperScan 애노테이션 사용 : java로 환경설정

@Configuration

@MapperScan("org.mybatis.spring.sample.mapper")

public class AppConfig {


  @Bean

  public DataSource dataSource() {

    return new EmbeddedDatabaseBuilder().addScript("schema.sql").build()

  }


  @Bean

  public SqlSessionFactory sqlSessionFactory() throws Exception {

    SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();

    sessionFactory.setDataSource(dataSource());

    return sessionFactory.getObject();

  }

}

  - MapperScannerConfigurer 사용 : 본 셋팅에는 해당 설정을 사용한다 

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">

  <property name="basePackage" value="com.mobiconsoft.dashboard.mapper" />

</bean>



2. pom.xml의 myBatis 버전 업그레이드 

  - mybatis-spring.jar 에서 1.2 이상의 최신 버전을 사용토록 한다 

<mybatis.spring.version>1.2.1</mybatis.spring.version>

<mysql.connector.version>5.1.27</mysql.connector.version>


<dependency>

<groupId>org.mybatis</groupId>

<artifactId>mybatis</artifactId>

<version>${mybatis.version}</version>

</dependency>

<dependency>

<groupId>org.mybatis</groupId>

<artifactId>mybatis-spring</artifactId>

<version>${mybatis.spring.version}</version>

</dependency>



3. myBatis Mapper 환경 설정

  - 위치를 webapp 폴더 밑으로 옮긴다 

    

  - dbpool-context.xml의 환경설정 변경 : id 명칭은 내부적으로 동일 이름을 사용하니 변경하지 말자 

<!-- mybatis sql session template -->

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

        <property name="dataSource" ref="dataSource" />

<property name="mapperLocations" value="classpath:mappers/*Mapper.xml" />

<property name="configLocation" value="/WEB-INF/mybatis-config.xml" />

</bean>


<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">

<constructor-arg ref="sqlSessionFactory" />

</bean>


<!-- mybatis mapper auto scanning -->

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">

<property name="basePackage" value="com.mobiconsoft.dashboard.mapper" />

</bean>

  - mybatis-config.xml 내역 수정

<configuration>

    <settings>

        <setting name="cacheEnabled" value="false" />

        <setting name="useGeneratedKeys" value="true" />

        <setting name="defaultExecutorType" value="REUSE" />

    </settings>

</configuration>

  - Person.xml 맵퍼 xml 파일명칭을 PersonMapper.xml 로 변경하고 WEB-INF/classes/mappers/ 폴더 밑으로 이동한다 

    + namespace는 반드시 PersonMapper interface 파일이 있는 위치를 명시한다 

    + resultType, parameterType 시에 full package + class 명칭을 명시한다 


<mapper namespace="com.mobiconsoft.dashboard.mapper.PersonMapper">

 

    <resultMap id="person" type="com.mobiconsoft.dashboard.domain.Person" >

        <result property="id" column="id"/>

        <result property="name" column="name"/>

    </resultMap>

 

    <select id="getPersons" resultType="com.mobiconsoft.dashboard.domain.Person">

        SELECT

        *

        FROM

        person

    </select>

 

    <select id="getPerson" parameterType="Integer" resultType="com.mobiconsoft.dashboard.domain.Person">

        SELECT

        *

        FROM

        person

        WHERE

        id=#{id}

    </select>

 

    <insert id="savePerson" parameterType="com.mobiconsoft.dashboard.domain.Person"

        INSERT INTO

        person(id, name)

        VALUES

        (#{id}, #{name})

    </insert>

    

    <update id="updatePerson" parameterType="com.mobiconsoft.dashboard.domain.Person"> 

        UPDATE 

        person 

        SET

        name=#{name}

        WHERE

        id=#{id} 

    </update>

 

    <delete id="deletePerson" parameterType="Integer">

        DELETE FROM

        person

        WHERE

        id=#{id}

    </delete>

 

</mapper>

  - 이제 PersonDAO.java interface를 PersonMapper.java로 바꾸어 보자 

    + PersonMapper.xml 에서 정의한 parameterType은 메소드의 파라미터 타입와 일치해야 한다

    + PersonMapper.xml 에서 정의한 resultType은 메소드의 리턴 타입과 일치해야 한다 

@Repository(value="personMapper")

public interface PersonMapper {

public List<Person> getPersons();

public Person getPerson(int id);

public void savePerson(Person person);

public void updatePerson(Person person);

public void deletePerson(int id);

}

  - grunt build 할 때 WEB-INF/ 밑의 모든 폴더/파일 dist 폴더에 copy하는 옵션 변경

copy: {

      dist: {

        files: [{

          expand: true,

          dot: true,

          cwd: '<%= yeoman.app %>',

          dest: '<%= yeoman.dist %>',

          src: [

            '*.{ico,png,txt,html}',

            '.htaccess',

            'bower_components/**/*',

            'images/{,*/}*.{gif,webp}',

            'styles/fonts/*',

            'WEB-INF/**/*'

          ]


  - PersonService Interface 제거하고 구현체를 PersonService로 변경하였음. 최종 소스 디렉토리 

    + controller : RESTful 요청 처리 

    + service : 실제 업무 트랜잭션 @Transactional 처리

    + mapper : myBatis mapper interface 

    + domain : 비즈니스 객체. 주로 테이블과 1:1 맵핑되는 Model

    

  - 실행

    

* 저장소 : https://github.com/ysyun/SPA_Angular_SpringFramework_Eclipse_ENV/tree/feature_mybatis_mapper



<참조>

  - myBatis Mapper 설정방법

posted by 윤영식
2013. 11. 20. 01:33 My Projects/BI Dashboard

데이터 저장소를 MySQL을 사용하며 CRUD를 위하여 MyBatis를 사용한다. Spring 프레임워크에서 사용하기 위한 설정과 사용법을 알아보자 



1. JDBC Pool 설정

  - tomcat 7을 사용하므로 tomcat의 jdbc-pool을 사용한다 (참조)

  - maven pom.xml : 이미 $TOMCAT_HOME/lib 밑에 라이브러리가 존재할 경우 provided 설정

<!-- spring jdbc dependency spring-tx -->

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-jdbc</artifactId>

<version>${spring.version}</version>

</dependency>


<!-- tomcat jdbc -->

<dependency>

<groupId>org.apache.tomcat</groupId>

<artifactId>tomcat-jdbc</artifactId>

<version>${tomcat.jdbc.version}</version>

<!--scope>provided</scope-->

</dependency>

  - spring context 와 properties 설정하기 

// web.xml 에서 dbpool-context.xml을 인식하기 위하여 설정변경

    <!-- root-context.xml, mybatis-context.xml -->

    <context-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>

            /WEB-INF/*-context.xml

        </param-value>

    </context-param>


// dbpool-context.xml 에서 properties 에서 환경값을 읽어서 설정한다 

// common-jdbc, c3po보다 tomcat의 jdbc-pool 성능이 더 좋다 

<bean

class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

<property name="locations">

<value>/WEB-INF/dbpool.properties</value>

</property>

</bean>


<bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource"

destroy-method="close">

<property name="driverClassName" value="${jdbc.driverClass}" />

<property name="url" value="${jdbc.url}" />

<property name="username" value="${jdbc.username}" />

<property name="password" value="${jdbc.password}" />

<property name="initialSize" value="${jdbc.min.size}" />

<property name="maxActive" value="${jdbc.max.size}" />

<property name="maxIdle" value="5" />

<property name="minIdle" value="2" />

</bean>


// dbpool.properties 내역 

jdbc.driverClass=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://localhost:3306/SolarDB?autoReconnect=true

jdbc.username=admin

jdbc.password=admin

jdbc.min.size=2

jdbc.max.size=10



2. Transaction 설정

  - @Transactional 애노테이션 기반으로 트랜잭션을 관리하고자 할 경우 설정

  - DAO 보다는 가급적 DAO를 호출하는 Service Interface의 Insert, Update, Delete 메소드 선언할 때 @Transactional 설정 (참조)

// dbpool-context.xml 에서 dataSource를 TransactionManager에 할당한다 

<!-- transaction manager -->

<context:annotation-config/>

<tx:annotation-driven transaction-manager="transactionManager" />

<bean id="transactionManager"

class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="dataSource" ref="dataSource"></property>

</bean>

  - @Transactional 사용시 Propagation 동작 방식에 대해서 숙지하자 (참조)

  - Spring과 그외 관련 설정 파일을 WEB-INF/spring 폴더로 위치 변경함

    



3. myBatis 설정

  - DataSource와 Transaction에 대한 설정이 끝났다면 myBatis를 설정한다 

  - MySQL을 사용할 것이다

  - myBatis의 Resource인 config와 mapper xml 파일은 src/main/resource로 이동하자 (Person.xml, mybatis-config.xml)

    


// dbpool-context.xml 에서 dataSource를 설정한다

// SqlSessionTemplate 을 DAO에서 사용할 것이다 

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

<property name="dataSource" ref="dataSource" />

<property name="configLocation" value="classpath:mybatis-config.xml" />

</bean>

<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">

<constructor-arg ref="sqlSessionFactory" />

</bean>



// mybatis-config.xml 에서 mapper.xml의 위치를 설정 

// Person.xml 과 같은 mapper xml을 여러개 열거 할 수 있다 

<configuration>

    <settings>

        <setting name="cacheEnabled" value="false" />

<setting name="useGeneratedKeys" value="true" />

<setting name="defaultExecutorType" value="REUSE" />

    </settings>

    

    <typeAliases>

        <typeAlias alias="Person" type="com.mobiconsoft.dashboard.domain.Person"></typeAlias>

    </typeAliases>

    

    <mappers>

        <mapper resource="com/mobiconsoft/dashboard/mybatis/mapper/Person.xml"></mapper>

    </mappers>

</configuration>

  - Mysql을 설치 및 Person Table을 하나 만들고 Mapper xml을 설정한다. 여기서는 예제로 Person.xml 파일 하나만 설정함 

// mysql 에서 테이블 생성하기 (참조)

mysql> create table person(

    -> id INT,

    -> name VARCHAR(30));


// Person.xml 맵핑 xml 내역 

// 호출 방법 ID : <namespace>.<id> ex) com.mobiconsoft.dashboard.person

<mapper namespace="com.mobiconsoft.dashboard.Person">

 

    <resultMap type="Person" id="PersonResult">

        <id property="id" column="id"/>

        <result property="name" column="name"/>

    </resultMap>

 

    <select id="getPersons" resultMap="PersonResult">

        SELECT

        *

        FROM

        person

    </select>

 

    <select id="getPerson" parameterType="Integer" resultMap="PersonResult">

        SELECT

        *

        FROM

        person

        WHERE

        id=#{id}

    </select>

 

    <insert id="savePerson" parameterType="Person"> <!-- useGeneratedKeys="true" keyProperty="id"> -->

        INSERT INTO

        person(id, name)

        VALUES

        (#{id}, #{name})

    </insert>

    

    <update id="updatePerson" parameterType="Person"

        UPDATE 

        person 

        SET

        name=#{name}

        WHERE

        id=#{id} 

    </update>

 

    <delete id="deletePerson" parameterType="Integer">

        DELETE FROM

        person

        WHERE

        id=#{id}

    </delete>

</mapper>

  - DAO와 DAO를 구현한다. 

// DAO Interface 

public interface PersonDAO {

  public List<Person> getPersons();

  public Person getPerson(int id);

  public Person savePerson(Person person);

  public Person updatePerson(Person person);

  public void deletePerson(int id);

}


// DAO Implementation

@Repository

public class PersonDAOImpl implements PersonDAO {

@Autowired

private SqlSession sqlSession;

private static final Logger logger = LoggerFactory.getLogger(PersonDAOImpl.class);

// end must be point . 

private static final String NS = "com.mobiconsoft.dashboard.Person.";


@Override

public List<Person> getPersons() {

logger.info("dao select all");

return sqlSession.selectList(NS+"getPersons");

}


@Override

public Person getPerson(int id) {

logger.info("dao select one id is " + id);

return sqlSession.selectOne(NS+"getPerson");

}


@Override

public Person savePerson(Person person) {

logger.info("dao save person is " + person);

sqlSession.insert(NS+"savePerson", person);

return person;

}

@Override

public Person updatePerson(Person person) {

logger.info("dao update person is " + person);

sqlSession.update(NS+"updatePerson", person);

return person;

}


@Override

public void deletePerson(int id) {

logger.info("dao delete id is " + id);

sqlSession.delete(NS+"deletePerson", id);

}

}

  - 기존 PersonServiceImpl의 내역을 변경한다 : @Transactional을 통하여 트랜잭션을 Service 레벨에서 관리한다 

@Service

public class PersonServiceImpl implements PersonService {


@Autowired

PersonDAO personDAO;

@Override

public List<Person> getPersons() {

return personDAO.getPersons();

}


@Override

public Person getById(Integer id) {

return personDAO.getPerson(id);

}


@Override

@Transactional

public Person save(Person person) {

personDAO.savePerson(person);

return person;

}

@Override

@Transactional

public Person update(Person person) {

personDAO.updatePerson(person);

return person;

}

@Override

@Transactional

public void delete(Integer id) {

personDAO.deletePerson(id);

}

}


* 저장소 : https://github.com/ysyun/SPA_Angular_SpringFramework_Eclipse_ENV/tree/feature_mybatis



<참조>

  - Spring, myBatis 설정 방법

  - Tomcat 7일 경우 Spring에서 Tomcat JDBC-Pool 사용하기

  - Common-JDBC와 C3P0와 Tomcat JDBC-Pool 성능차이

  - Transaction Manager 선언적으로 사용하기

  - Transaction Propagation 동작 방식

  - Mac에서 기존 MySQL 삭제하기 

posted by 윤영식
prev 1 next