IK.AM

@making's tech note


Doma+Springの連携サンプル

🗃 {Programming/Java/org/seasar/doma}
🗓 Updated at 2013-08-17T00:04:54Z  🗓 Created at 2013-08-17T00:04:54Z   🌎 English Page

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

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

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

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);
    }

}

✒️️ Edit  ⏰ History  🗑 Delete