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