728x90
반응형

이전에 작성했던 "Embedded Databases 사용하기 - <jdbc:embedded-database>"에서는 Test Case 작성 시 JdbcTemplate 을 사용했었다. 이 예제에서는 JdbcTemplate 대신 MyBatis 를 사용하도록 변경하고, select 외에 insert/update/delete 기능들도 추가로 테스트해 보도록 하겠다. 따라서 "Embedded Databases 사용하기 - <jdbc:embedded-database>" 를 먼저 읽어보는 것이 좋다.

Maven Dependencies

"Embedded Databases 사용하기 - <jdbc:embedded-database>" 예제의 Dependency 에 mybatis, mybatis-spring, log4jdbc-remix, slf4j-log4j12 를 추가하였다. mybatis 와 mybatis-spring 은 mybatis 를 사용하기 위한 필수 Dependency 이며,  log4jdbc-remix, slf4j-log4j12 는 선택사항이다. log4jdbc-remix, slf4j-log4j12 를 추가한 이유에 대해서는 log4j.xml 설정을 설명할 때 언급하도록 하겠다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<properties>
    <org.springframework-version>4.0.6.RELEASE</org.springframework-version>
    <hsqldb-version>1.8.0.10</hsqldb-version>
    <mybatis-version>3.2.7</mybatis-version>
    <mybatis.spring-version>1.2.2</mybatis.spring-version>
    <org.slf4j-version>1.7.7</org.slf4j-version>
    <log4jdbc-version>0.2.7</log4jdbc-version>
    <junit.version>4.10</junit.version>
    <org.hamcrest.version>1.1</org.hamcrest.version>
</properties>
 
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${org.springframework-version}</version>
    </dependency>
     
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>${org.springframework-version}</version>
    </dependency>
 
    <dependency>
        <groupId>hsqldb</groupId>
        <artifactId>hsqldb</artifactId>
        <version>${hsqldb-version}</version>
    </dependency>
     
    <!-- MyBatis Dependencies -->
    <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>
 
    <!-- Log Dependencies-->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>${org.slf4j-version}</version>
    </dependency>
     
    <dependency>
        <groupId>org.lazyluke</groupId>
        <artifactId>log4jdbc-remix</artifactId>
        <version>${log4jdbc-version}</version>
    </dependency>
     
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>${org.springframework-version}</version>
    </dependency>
     
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>${junit.version}</version>
        <scope>test</scope>
    </dependency>
     
    <dependency>
        <groupId>org.hamcrest</groupId>
        <artifactId>hamcrest-all</artifactId>
        <version>${org.hamcrest.version}</version>
        <scope>test</scope>
    </dependency>

 

applicationContext.xml 설정

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?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:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:oxm="http://www.springframework.org/schema/oxm"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd">
 
    <context:component-scan base-package="com.happyhouse.rednics" />
 
    <jdbc:embedded-database id="embdDataSource" type="HSQL">
        <jdbc:script location="classpath:/schema.sql" />
        <jdbc:script location="classpath:/data.sql" />
    </jdbc:embedded-database>
     
    <!-- Custom sql formatter  -->
    <bean id="dataSource" class="net.sf.log4jdbc.Log4jdbcProxyDataSource">
        <constructor-arg ref="embdDataSource" />
        <property name="logFormatter">
            <bean class="net.sf.log4jdbc.tools.Log4JdbcCustomFormatter">
                <property name="loggingType" value="MULTI_LINE" />
                <property name="sqlPrefix" value="[SQL] " />
            </bean>
        </property>
    </bean>
     
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:/mybatis.xml" />
        <property name="typeAliasesPackage" value="com.happyhouse.rednics.tutorial.spring.mybatis.dto" />
    </bean>
     
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate" destroy-method="clearCache">
        <constructor-arg index="0" ref="sqlSessionFactory" />
    </bean>
     
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.happyhouse.rednics.tutorial.spring.mybatis.dao" />
    </bean>
     
</beans>

 

"Embedded Databases 사용하기 - <jdbc:embedded-database>" 에 추가된 내용은 다음과 같다.

1. Log4jdbcProxyDataSource 빈 추가 (옵션)

SQL 로그 포멧을 커스터마이징 하기 위해서 추가했다. <jdbc:embedded-database> 태그로 정의한 dataSource(embdDataSource) 를, 생성자의 파라메터로 받고 있다.  이 빈은 SqlSessionFactoryBean 의 dataSource 프로퍼티에 설정한다. SQL 로그 커스터 마이징 기능을 원하지 않는다면 <jdbc:embedded-database> 로 정의한 dataSource 를    SqlSessionFactoryBean 에 바로 설정하는 것도 가능하다.

2. SqlSessionFactoryBean 빈 추가 (필수)

MyBatis 를 사용하기 위해서는 꼭 추가해야 할 빈 중에 하나이다. configLocation 프로퍼티에는 mybatis 설정 파일의 위치를 지정한다. typeAliasesPackage 프로퍼티에는 DTO 클래스가 존재하는 패키지명을 콤마로 구분해 가면서 설정하면 된다. typeAliasesPackage 프로퍼티에 com.happyhouse.rednics.tutorial.spring.mybatis.dto 를 설정하게 되면, 이 패키지 밑에 존재하는 클래스의 이름을 Mapper 정의 파일(UserDao.xml)의 resultType 과 parameterType 어트리뷰트에 바로 사용할 수 있게 된다.아래 작성된 UserDao.xml 파일의 resultType 과 parameterType 에서 사용되는 "User" 라는 값에 주목하자. 따라서 이 예제에서는 mybatis 설정파일에 <typeAliases> 및 하위의 <typeAlias> 태그를 사용할 필요가 없다.

3. SqlSessionTemplate 빈 추가 (필수)

SqlSessionFactoryBean 과 함께 MyBatis 를 사용하기 위해서 꼭 추가해야 하는 빈이다. SqlSessionFactoryBean 으로 생성한 빈을 생성자 파라메터로 받고 있다.

4. MapperScannerConfigurer 추가 (옵션이나, 개인적으로 필수적인 빈이라 생각함)

아래 MyBatis 설정파일을 보면 일반적으로 사용하는 <mappers> 와 하위의 <mapper> 태크를 사용하지 않고 있다. MapperScannerConfigurer 를 설정했기 때문에 사용할 필요가 없는 것이다. basePackage 프로퍼티에 Mapper 설정파일이 존재하는 패키지명들을 콤마로 구분하여 설정하면, 자동으로 검색되기 때문이다. 이렇게 자동설정된 Mapper(UserDao) 는 서비스의 구현체등에 Autowiire 를 통해서 DI 도 가능하게 된다. MapperScannerConfigurer 를 사용함으로써 아래 UserService 구현체 소스에서 UserDAO 가 바로 DI 가능하게 되었음에 주목하자. 

mybatis.xml 설정 (MyBatis 설정파일)

이 설정 파일에서는 <typeAliases> 와 <mapper> 태그를 사용하지 않는다. SqlSessionFactoryBean 의 typeAliasesPackage 프로퍼티와 MapperScannerConfigurer 의 basePackage 프로퍼티 설정을 사용해서 생략 가능한 태그들이기 때문이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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>
    <settings>
        <setting name="cacheEnabled" value="true" />
        <setting name="lazyLoadingEnabled" value="true" />
        <setting name="multipleResultSetsEnabled" value="true" />
        <setting name="useColumnLabel" value="true" />
        <setting name="defaultStatementTimeout" value="25000" />
    </settings>
</configuration>

 

schema.sql 작성

1
2
3
4
5
6
7
8
9
10
create schema happyhouse AUTHORIZATION DBA;
set schema happyhouse;
 
drop table tbl_user if exists;
 
CREATE TABLE tbl_user (
  id varchar(40) NOT NULL,
  username varchar(45) NOT NULL,
  password varchar(45) NOT NULL
);

 

data.sql 작성

1
insert into tbl_user values('rednics', 'Shin Kwan Young', '1234');

 

User 클래스 작성 (DTO)

위에서 생성한 tbl_user 테이블의 컬럼정의와 동일한 User 클래스를 작성한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.happyhouse.rednics.tutorial.spring.mybatis.dto;
 
public class User {
     
    private String id;
    private String username;
    private String password;
     
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
     
}

 

 

UserDao 인터페이스 작성 (MyBatis Mapper 인터페이스)

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.happyhouse.rednics.tutorial.spring.mybatis.dao;
 
import java.util.List;
 
import com.happyhouse.rednics.tutorial.spring.mybatis.dto.User;
 
public interface UserDao {
 
    public List<User> selectAllUsers();
    public int insertUser(User user);
    public int updateUser(User user);
    public int deleteUser(User user);
}

 

UserDao.xml 설정 (MyBatis Mapper 설정파일)

위에서 설명했지만 resultType 과 parameterType 에 설정하고 있는 "User" 는, SqlSessionFactoryBean 설정의 typeAliasesPackage 프로퍼티에 설정한 패키지 내부에 존재하는 User 라는 클래스의 이름이다. MyBatis 설정파일에  <typeAliases> 태크를 사용하지 않고도 typeAlias 와 동일한 효과를 볼 수 있는 것이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version="1.0" encoding="UTF-8" ?>
 <!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://www.mybatis.org/dtd/mybatis-3-mapper.dtd">
 
<mapper namespace="com.happyhouse.rednics.tutorial.spring.mybatis.dao.UserDao">
 
    <select id="selectAllUsers" resultType="User">
        SELECT * FROM happyhouse.tbl_user
    </select>
 
    <insert id="insertUser" parameterType="User">
        INSERT INTO happyhouse.tbl_user VALUES(
            #{id},
            #{username},
            #{password}
        )
    </insert>
 
    <update id="updateUser" parameterType="User">
        UPDATE happyhouse.tbl_user
        SET username = #{username},
            password = #{password}
        WHERE id = #{id}
    </update>
     
    <delete id="deleteUser" parameterType="User">   
        DELETE FROM happyhouse.tbl_user
        WHERE id = #{id}
    </delete>
     
</mapper>

 

UserService 인터페이스 작성

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.happyhouse.rednics.tutorial.spring.mybatis.service;
 
import java.util.List;
 
import com.happyhouse.rednics.tutorial.spring.mybatis.dto.User;
 
public interface UserService {
 
    public List<User> selectAllUsers();
    public int insertUser(User user);
    public int updateUser(User user);
    public int deleteUser(User user);
}

 

UserServiceImpl(UserService 구현체) 작성

MapperScannerConfigurer 빈 설정을 통해 UserDao(MyBatis Mapper) 가 UserService 구현체에 직접 DI 되고 있는 점에 주목하자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.happyhouse.rednics.tutorial.spring.mybatis.service;
 
import java.util.List;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
import com.happyhouse.rednics.tutorial.spring.mybatis.dao.UserDao;
import com.happyhouse.rednics.tutorial.spring.mybatis.dto.User;
 
@Service
public class UserServiceImpl implements UserService {
     
    @Autowired
    private UserDao userDao;
 
    @Override
    public List<User> selectAllUsers() {
        return userDao.selectAllUsers();
    }
 
    @Override
    public int insertUser(User user) {
        return userDao.insertUser(user);
    }
 
    @Override
    public int updateUser(User user) {
        return userDao.updateUser(user);
    }
 
    @Override
    public int deleteUser(User user) {
        return userDao.deleteUser(user);
    }
 
}

 

Test Case 작성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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 com.happyhouse.rednics.tutorial.spring.mybatis.dto.User;
import com.happyhouse.rednics.tutorial.spring.mybatis.service.UserService;
 
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/applicationContext.xml")
public class MyBatisTest {
     
    @Autowired
    private UserService userService;
     
    @Test
    public void test() {
        userService.selectAllUsers();
         
        User user = new User();
         
        addUser(user);
        userService.selectAllUsers();
         
        modifyUser(user);
        userService.selectAllUsers();
         
        removeUser(user);
        userService.selectAllUsers();
    }
     
    private void addUser(User user) {
        user.setId("id2");
        user.setUsername("username2");
        user.setPassword("password2");
         
        userService.insertUser(user);
    }
     
    private void modifyUser(User user) {
        user.setId("id2");
        user.setUsername("username_modified");
        user.setPassword("password_modified");
         
        userService.updateUser(user);
    }
     
    private void removeUser(User user) {
        user.setId("id2");
        user.setUsername("username_modified");
        user.setPassword("password_modified");
         
        userService.deleteUser(user);
    }
}

 

log4j.xml 설정

Maven Dependencies 에서 설명할 때 log4jdbc-remix, slf4j-log4j12 는 선택항목이라고 말한적이 있다. 이 두 Dependency 와 아래의 log4j 설정을 사용하게 되면 각 SQL 및 파라메터를 로그로 확인할 수 있으며 select 쿼리의 실행결과인 ResultSet 을 아래 실행결과와 같이 테이블형태로 볼 수 있게 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
 
    <appender name="console" class="org.apache.log4j.ConsoleAppender">
        <param name="Target" value="System.out" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern"
                value="%d{[yyyy-MM-dd] [HH:mm:ss]} [%-5p] [%t] [%s] [%C] [%M] : %m%n" />
        </layout>
    </appender>
 
    <logger name="jdbc.resultsettable">
        <level value="info" />
    </logger>
     
    <logger name="jdbc.sqlonly">
        <level value="info" />
    </logger>
 
    <logger name="net.sf.log4jdbc">
        <level value="info" />
    </logger>
     
    <logger name="com.happyhouse.rednics.tutorial.spring.mybatis.service">
        <level value="info" />
    </logger>
 
    <root>
        <priority value="info" />
        <appender-ref ref="console" />
    </root>
 
</log4j:configuration>

 

실행결과

실재 로그는 select/insert/update/delete 관련 SQL, 관련 파라메터 및 다양한 디버깅 정보등을 포함하고 있으나 여기서는 주요 정보만을 추려서 보여주고 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1. addUser 수행 전
|--------|----------------|---------|
|ID      |USERNAME        |PASSWORD |
|--------|----------------|---------|
|rednics |Shin Kwan Young |1234     |
|--------|----------------|---------|
 
2. addUser 수행 후
|--------|----------------|----------|
|ID      |USERNAME        |PASSWORD  |
|--------|----------------|----------|
|rednics |Shin Kwan Young |1234      |
|id2     |username2       |password2 |
|--------|----------------|----------|
 
3. modifyUser 수행 후
|--------|------------------|------------------|
|ID      |USERNAME          |PASSWORD          |
|--------|------------------|------------------|
|rednics |Shin Kwan Young   |1234              |
|id2     |username_modified |password_modified |
|--------|------------------|------------------|
 
 
4. removeUser 수행 후
|--------|----------------|---------|
|ID      |USERNAME        |PASSWORD |
|--------|----------------|---------|
|rednics |Shin Kwan Young |1234     |
|--------|----------------|---------|

 

728x90
반응형

'SQL > HSQLDB' 카테고리의 다른 글

HSQL 관리 툴  (0) 2015.03.04
Embedded Databases 사용하기 - <jdbc:embedded-database>  (0) 2015.03.04
블로그 이미지

nineDeveloper

안녕하세요 현직 개발자 입니다 ~ 빠르게 변화하는 세상에 뒤쳐지지 않도록 우리모두 열심히 공부합시다 ~! 개발공부는 넘나 재미있는 것~!

,