이전에 작성했던 "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;@Servicepublic 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 ||--------|----------------|---------| |
'SQL > HSQLDB' 카테고리의 다른 글
| HSQL 관리 툴 (0) | 2015.03.04 |
|---|---|
| Embedded Databases 사용하기 - <jdbc:embedded-database> (0) | 2015.03.04 |