2012年1月9日月曜日

Spring3 + MyBatis3

MyBatis3がMyBatis2に比べて結構使いやすくなっています。
特に実装クラスを必要としないMapperの機能が便利です。
他には、XMLでognl式が使えたり、使いやすいタグが増えています。

Spring3 + MyBatis3の実装例で試してみます。

まず、データクラスを作成します。

User.java
  1. package com.brightgenerous.sample.application.bean;  
  2.   
  3. import java.io.Serializable;  
  4.   
  5. public class User implements Serializable {  
  6.   
  7.     private static final long serialVersionUID = -1056270813521861315L;  
  8.   
  9.     private Integer m_id;  
  10.   
  11.     private String m_name;  
  12.   
  13.     private String m_email;  
  14.   
  15.     public Integer getId() {  
  16.         return m_id;  
  17.     }  
  18.   
  19.     public void setId(Integer x_id) {  
  20.         m_id = x_id;  
  21.     }  
  22.   
  23.     public String getName() {  
  24.         return m_name;  
  25.     }  
  26.   
  27.     public void setName(String x_name) {  
  28.         m_name = x_name;  
  29.     }  
  30.   
  31.     public String getEmail() {  
  32.         return m_email;  
  33.     }  
  34.   
  35.     public void setEmail(String x_email) {  
  36.         m_email = x_email;  
  37.     }  
  38. }  

次に、Dao(Mapper)インターフェースを作成します。

UserDao.java
  1. package com.brightgenerous.sample.application.dao;  
  2.   
  3. import com.brightgenerous.sample.application.bean.User;  
  4.   
  5. public interface UserDao {  
  6.   
  7.     User select(User x_user);  
  8.   
  9.     int insert(User x_user);  
  10.   
  11.     int update(User x_user);  
  12.   
  13.     int delete(User x_user);  
  14. }  

そして、UserDao.javaと同じパッケージにUserDao.xmlを置きます。(拡張子以外のファイル名を同じにする)
それだけでインターフェースとXMLファイルが関連付けられます。

UserDao.xml
  1. <!--xml version="1.0" encoding="UTF-8" ?-->  
  2. <!--DOCTYPE mapper PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN" "http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd"-->  
  3.   
  4. <mapper namespace="com.brightgenerous.sample.application.dao.UserDao">  
  5.   
  6.  <cache flushinterval="3600000">  
  7.   
  8.  <resultmap type="User" id="User">  
  9.   <result column="id" property="id">  
  10.   <result column="name" property="name">  
  11.   <result column="email" property="email">  
  12.  </result></result></result></resultmap>  
  13.   
  14.  <select id="select" parametertype="User" resulttype="User" resultmap="User">  
  15.   select  
  16.    *  
  17.   from  
  18.    t_user  
  19.     
  20.      
  21.     and 1 = 0  
  22.     and id = #{id}  
  23.      
  24.     
  25.  </select>  
  26.   
  27.  <insert id="insert" parametertype="User">  
  28.   <selectkey keyproperty="id" resulttype="Integer" order="BEFORE">  
  29.    select coalesce((select max(id) from t_user),0) + 1 as id  
  30.   </selectkey>  
  31.   insert into  
  32.    t_user (  
  33.     id,  
  34.     name,  
  35.     email  
  36.    ) values (  
  37.     #{id},  
  38.     #{name},  
  39.     #{email}  
  40.    )  
  41.  </insert>  
  42.   
  43.  <update id="update" parametertype="User">  
  44.   update  
  45.    t_user  
  46.   set  
  47.    name = #{name},  
  48.    email = #{email}  
  49.   where  
  50.    id = #{id}  
  51.  </update>  
  52.   
  53.  <delete id="delete" parametertype="User">  
  54.   delete from  
  55.    t_user  
  56.   where  
  57.    id = #{id}  
  58.  </delete>  
  59.   
  60. </cache></mapper>  

最後に、トランザクション境界となるServiceクラスを作成します。

UserService.java
  1. package com.brightgenerous.sample.application.service;  
  2.   
  3. import javax.inject.Inject;  
  4.   
  5. import com.brightgenerous.sample.application.bean.User;  
  6. import com.brightgenerous.sample.application.dao.UserDao;  
  7.   
  8. public class UserService {  
  9.   
  10.     @Inject  
  11.     private UserDao m_userDao;  
  12.   
  13.     public User get(User x_user) {  
  14.         return m_userDao.select(x_user);  
  15.     }  
  16.   
  17.     public void update(User x_user) {  
  18.         m_userDao.update(x_user);  
  19.     }  
  20. }  

あとは設定ファイルを書くだけです。
注入先フィールドのInjectアノテーションはjavax.inject.Injectです。
実は、上記のすべてのクラスでMyBatisやSpringに関するインポートがないのです。

applicationContext.xml
  1. <!--xml version="1.0" encoding="UTF-8" ?-->  
  2. <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:jee="http://www.springframework.org/schema/jee" xsi:schemalocation="  
  3.    http://www.springframework.org/schema/beans  
  4.    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd  
  5.    http://www.springframework.org/schema/context  
  6.    http://www.springframework.org/schema/context/spring-context-3.1.xsd  
  7.    http://www.springframework.org/schema/jee  
  8.    http://www.springframework.org/schema/jee/spring-jee-3.1.xsd">  
  9.   
  10.  <!-- DATABASE CONFIG -->  
  11.  <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
  12.   <property name="locations" value="classpath:database.properties">  
  13.  </property></bean>  
  14.   
  15.  <!-- DATA SOURCE -->  
  16.  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">  
  17.   <property name="driverClassName" value="${jdbc.driverClassName}">  
  18.   <property name="url" value="${jdbc.url}">  
  19.   <property name="username" value="${jdbc.username}">  
  20.   <property name="password" value="${jdbc.password}">  
  21.   <property name="defaultAutoCommit" value="true">  
  22.   <property name="removeAbandoned" value="true">  
  23.  </property></property></property></property></property></property></bean>  
  24.   
  25.  <!-- TRANSACTION -->  
  26.  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
  27.   <property name="dataSource" ref="dataSource">  
  28.  </property></bean>  
  29.  <bean id="transactionAttributeSource" class="org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource">  
  30.   <property name="properties">  
  31.    <props>  
  32.     <prop key="regist*">PROPAGATION_REQUIRED</prop>  
  33.     <prop key="update*">PROPAGATION_REQUIRED</prop>  
  34.     <prop key="delete*">PROPAGATION_REQUIRED</prop>  
  35.     <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>  
  36.    </props>  
  37.   </property>  
  38.  </bean>  
  39.  <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">  
  40.   <property name="transactionManager" ref="transactionManager">  
  41.   <property name="transactionAttributeSource" ref="transactionAttributeSource">  
  42.  </property></property></bean>  
  43.  <bean id="beanNameAutoProxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">  
  44.   <property name="interceptorNames" value="transactionInterceptor">  
  45.   <property name="beanNames" value="*Service">  
  46.  </property></property></bean>  
  47.   
  48.  <!-- MYBATIS3 SPRING3 -->  
  49.  <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  
  50.   <property name="configLocation" value="classpath:sqlMapConfig.xml">  
  51.   <property name="dataSource" ref="dataSource">  
  52.  </property></property></bean>  
  53.   
  54.  <!-- PACKAGE IMPLEMENTS -->  
  55.  <context:component-scan base-package="com.brightgenerous.sample.application.service" name-generator="com.brightgenerous.extension.spring3.FqcnBeanNameGenerator" use-default-filters="false">  
  56.   <context:include-filter type="regex" expression=".*Service">  
  57.  </context:include-filter></context:component-scan>  
  58.  <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">  
  59.   <property name="basePackage" value="com.brightgenerous.sample.application.dao">  
  60.  </property></bean>  
  61.   
  62. </beans>  

applicationContext.xmlには com.brightgenerous.extension.spring3.FqcnBeanNameGeneratorというクラスがありますが、
これは、ただFQCNを返すだけのSpringのBeanNameGenerator実装です。
database.propertiesファイルは特にここで書くほどでもないので省略します。

sqlMapConfig.xml
  1. <!--xml version="1.0" encoding="UTF-8" ?-->  
  2. <!--DOCTYPE configuration PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN" "http://ibatis.apache.org/dtd/ibatis-3-config.dtd"-->  
  3.   
  4. <configuration>  
  5.   
  6.  <settings>  
  7.   <setting name="cacheEnabled" value="true">  
  8.   <setting name="lazyLoadingEnabled" value="true">  
  9.   <setting name="multipleResultSetsEnabled" value="true">  
  10.   <setting name="aggressiveLazyLoading" value="true">  
  11.   <setting name="useColumnLabel" value="true">  
  12.   <setting name="useGeneratedKeys" value="false">  
  13.   <setting name="autoMappingBehavior" value="PARTIAL">  
  14.   <setting name="defaultExecutorType" value="REUSE">  
  15.   <setting name="safeRowBoundsEnabled" value="true">  
  16.   <setting name="mapUnderscoreToCamelCase" value="false">  
  17.  </setting></setting></setting></setting></setting></setting></setting></setting></setting></setting></settings>  
  18.   
  19.  <typealiases>  
  20.   <package name="com.brightgenerous.sample.application.bean">  
  21.  </package></typealiases>  
  22.   
  23. </configuration>  

実行方法は以下のようになります。

UserServiceTestSpring
  1. package com.brightgenerous.sample.application.service;  
  2.   
  3. import com.brightgenerous.sample.application.bean.User;  
  4. import com.brightgenerous.sample.application.dao.UserDao;  
  5.   
  6. import org.junit.Before;  
  7. import org.junit.Test;  
  8. import org.springframework.context.ApplicationContext;  
  9. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  10.   
  11. public class UserServiceTestSpring {  
  12.   
  13.     private ApplicationContext context;  
  14.   
  15.     @Before  
  16.     public void before() {  
  17.         context = new ClassPathXmlApplicationContext("applicationContext.xml");  
  18.     }  
  19.   
  20.     @Test  
  21.     public void test01() {  
  22.         UserService service = context.getBean(UserService.class);  
  23.         User user = new User();  
  24.         user.setId(Integer.valueOf(1));  
  25.         user = service.get(user);  
  26.         user.setName(user.getName() + "-");  
  27.         service.update(user);  
  28.     }  
  29. }  

これ以上ソースコードの記述量を減らせないんじゃないのかと思えるほど、簡単になりました。
設定ファイルは一度書いてしまえば、以降は編集しないので、 実際に作成するファイルはデータクラス、Mapperインターフェース、MapperのXMLファイル、サービスクラスの4つです。

次回は、SpringをGuiceに置き換えて同じ機能を実現してみようと思います。
具体的には、Springでの設定ファイルにあたる部分をソースで書くだけで、Mapperやサービスクラスには手を加えません。

1 件のコメント: