---
title: Doma+Springの連携サンプル
tags: []
categories: ["Programming", "Java", "org", "seasar", "doma"]
date: 2013-08-17T00:04:54Z
updated: 2013-08-17T00:04:54Z
---

DomaとSpringを連携するサンプルをぐぐっても、えらく古い記事しかヒットしなかったので残しておく。

サンプルソースは[Github][1]においた。

基本はGuiceと同じで[http://doma.seasar.org/reference/config.html#DIコンテナを利用する場合の設定例][2]の通り

    package sample.dao;
    
    import javax.inject.Inject;
    
    import org.seasar.doma.AnnotateWith;
    import org.seasar.doma.Annotation;
    import org.seasar.doma.AnnotationTarget;
    import org.seasar.doma.Dao;
    import org.seasar.doma.Select;
    import org.seasar.doma.Update;
    import org.springframework.stereotype.Repository;
    
    import sample.entity.Employee;
    
    @Dao
    @AnnotateWith(annotations = {
    		@Annotation(target = AnnotationTarget.CLASS, type = Repository.class),
    		@Annotation(target = AnnotationTarget.CONSTRUCTOR, type = Inject.class) })
    public interface EmployeeDao {
    
    	@Select
    	Employee selectById(Integer employeeId);
    
    	@Update
    	int update(Employee employee);
    }


生成されるクラスに`@Repository`をつけ、コンストラクタに`@Inject`をつけてBean定義した`org.seasar.doma.jdbc.Config`をautowireさせれば良い。

aptによって以下のようなコードが生成される

    @org.springframework.stereotype.Repository()
    @javax.annotation.Generated(value = { "Doma", "1.31.0" }, date = "2013-08-15T02:14:34.026+0900")
    public class EmployeeDaoImpl extends org.seasar.doma.internal.jdbc.dao.AbstractDao implements sample.dao.EmployeeDao {
    
        static {
            org.seasar.doma.internal.Artifact.validateVersion("1.31.0");
        }
    
        private static final java.lang.reflect.Method __method1 = org.seasar.doma.internal.jdbc.dao.AbstractDao.__getDeclaredMethod(sample.dao.EmployeeDao.class, "update", sample.entity.Employee.class);
    
        /**
         * @param config the config
         */
        @javax.inject.Inject()
        public EmployeeDaoImpl(org.seasar.doma.jdbc.Config config) {
            super(config);
        }
        
        // ...
    }

Bean定義は以下。JavaConfigを使うと、Configクラスを匿名で実装できて楽。

    package sample;
    
    import javax.sql.DataSource;
    
    import org.seasar.doma.jdbc.Config;
    import org.seasar.doma.jdbc.DomaAbstractConfig;
    import org.seasar.doma.jdbc.dialect.Dialect;
    import org.seasar.doma.jdbc.dialect.H2Dialect;
    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.jdbc.datasource.TransactionAwareDataSourceProxy;
    import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
    import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    @Configuration
    @ComponentScan(basePackages = "sample")
    @EnableTransactionManagement
    public class BeanConfig {
    	@Bean
    	public DataSource dataSource() {
    		DataSource dataSource = new EmbeddedDatabaseBuilder()
    				.setType(EmbeddedDatabaseType.H2)
    				.addScript("classpath:/database/schema.sql")
    				.addScript("classpath:/database/dataload.sql").build();
    		return dataSource;
    	}
    
    	@Bean
    	public PlatformTransactionManager transactionManager() {
    		return new DataSourceTransactionManager(dataSource());
    	}
    
    	@Bean
    	public Dialect dialect() {
    		return new H2Dialect();
    	}
    
    	@Bean
    	public Config domaConfig() {
    		return new DomaAbstractConfig() {
    			@Override
    			public Dialect getDialect() {
    				return dialect();
    			}
    
    			@Override
    			public DataSource getDataSource() {
    				return new TransactionAwareDataSourceProxy(dataSource());
    			}
    		};
    	}
    }

daoパッケージをcomponent-scanの対象にすること。
DIコンテナと連携するとDataSourceやDialectの設定を外出し出来て良いですね。

**2014-03-24追記**

Domaが`dataSource.getConnection()`を実行した際に、新規`Connection`が開かないようにDomaConfigで`DataSource`を返す際は`TransactionAwareDataSourceProxy`でラップする必要がある点に注意。

**ここまで**

XMLファイルで定義する場合は以下のようにする。

    <?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:jdbc="http://www.springframework.org/schema/jdbc"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
    		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
        <context:component-scan base-package="sample" />
        <tx:annotation-driven />
    
        <jdbc:embedded-database id="dataSource" type="H2">
            <jdbc:script location="classpath:/database/schema.sql" />
            <jdbc:script location="classpath:/database/dataload.sql" />
        </jdbc:embedded-database>
    
        <bean id="transactionManager"
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager" />
    
        <bean id="dialect" class="org.seasar.doma.jdbc.dialect.H2Dialect" />
    
        <bean id="domaConfig" class="xxx.yyy.zzz.DomaConfig">
            <property name="dataSource" ref="dataSource" />
            <property name="dialect" ref="dialect" />
        </bean>
    </beans>

トランザクション管理はDaoクラスの外のServiceクラスで行った方が良いと思う。

    package sample.service;
    
    import javax.inject.Inject;
    
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    import sample.dao.EmployeeDao;
    import sample.entity.Employee;
    
    @Service
    public class EmployeeService {
    
    	@Inject
    	protected EmployeeDao employeeDao;
    
    	public Employee selectById(Integer employeeId) {
    		return employeeDao.selectById(employeeId);
    	}
    
    	@Transactional
    	public int update(Employee employee) {
    		return employeeDao.update(employee);
    	}
    
    }

  [1]: https://github.com/making/doma-spring-example
  [2]: http://doma.seasar.org/reference/config.html#DIコンテナを利用する場合の設定例
