26
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

Spring bootでマルチデータソース対応の実装方法(MybatisとSpring Data JPA )

Spring bootでマルチデータソースを利用する場合の実装方法を整理します。

Mybatisの場合

Autoconfigを利用するので、application.propertiesにDBの接続情報を記載します。

application.properties
#プライマリーDB
spring.datasource.url=jdbc:mysql://localhost:3306/primary_db?useSSL=false
spring.datasource.username=demo
spring.datasource.password=demo
spring.datasource.driverClassName=com.mysql.jdbc.Driver

#セカンダリーDB
secondary.datasource.url=jdbc:mysql://localhost:3306/secondary_db?useSSL=false
secondary.datasource.username=demo
secondary.datasource.password=demo
secondary.datasource.driverClassName=com.mysql.jdbc.Driver

通常の通りにSpring bootのmainクラスを作成します。

DemoApplication
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args).close();
    }
}

プライマリーdataSourceとsqlSessionを定義します。
 ・リポジトリクラスのbasepackage
 ・SQLMapの格納フォルダ

PrimaryDbConfig
@Configuration
@MapperScan(basePackages = PrimaryDbConfig.BASE_PACKAGES
            , sqlSessionTemplateRef = "primarySqlSessionTemplate")
public class PrimaryDbConfig {
    public static final String BASE_PACKAGES = "com.example.demo.primary";
    public static final String MAPPER_XML_PATH = "classpath:com/example/demo/primary/*.xml";

    @Primary
    @Bean(name = "primaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {
        return new DataSource();
    }

    @Primary
    @Bean(name = "primarySqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("primaryDataSource") DataSource primaryDataSource)
            throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(primaryDataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_XML_PATH));
        return bean.getObject();
    }

    @Bean(name = "primarySqlSessionTemplate")
    public SqlSessionTemplate sqlSessionTemplate(
            @Qualifier("primarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

上記と同様にセカンダリーdataSourceとsqlSessionを定義します。

SecondaryDbConfig
@Configuration
@MapperScan(basePackages = SecondaryDbConfig.BASE_PACKAGES
            , sqlSessionTemplateRef = "secondarySqlSessionTemplate")
public class SecondaryDbConfig {
    public static final String BASE_PACKAGES = "com.example.demo.secondary";
    public static final String MAPPER_XML_PATH = "classpath:com/example/demo/secondary/*.xml";

    @Bean(name = "secondaryDataSource")
    @ConfigurationProperties(prefix = "secondary.datasource")
    public DataSource dataSource() {
        return new DataSource();
    }

    @Bean(name = "secondarySqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("secondaryDataSource") DataSource secondaryDataSource)
            throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(secondaryDataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_XML_PATH));
        return bean.getObject();
    }

    @Bean(name = "secondarySqlSessionTemplate")
    public SqlSessionTemplate sqlSessionTemplate(
            @Qualifier("secondarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

それぞれのリポジトリクラスを作成します。

PrimaryRepository
@Mapper
public interface PrimaryRepository {
    public long selectCountFromPrimary();
}
SecondaryRepository
@Mapper
public interface SecondaryRepository {
    public long selectCountFromSecondary();
}

以下のリソースフォルダにプライマリーのSqlMapを定義します。

com
 |-example
     |-demo
         |-primary
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.example.demo.primary.PrimaryRepository">

    <select id="selectCountFromPrimary" resultType="long">
        select count(*) from emp;
    </select>
</mapper>

以下のリソースフォルダにセカンダリーのSqlMapを定義します。

com
 |-example
     |-demo
         |-secondary
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.example.demo.secondary.SecondaryRepository">

    <select id="selectCountFromSecondary" resultType="long">
        select count(*) from emp2;
    </select>
</mapper>

上記リポジトリを呼び出し、SQLを実行します。

    @Autowired
    private PrimaryRepository primaryRepository;
    @Autowired
    private SecondaryRepository secondaryRepository;

    ...
    long countPrimary = primaryRepository.selectCountFromPrimary();
    long countSecondary = secondaryRepository.selectCountFromSecondary();

Spring Data JPAの場合

Mybatisと同様にapplication.propertiesにDBの接続情報を記載します。

application.properties
#プライマリーDB
spring.datasource.url=jdbc:mysql://localhost:3306/primary_db?useSSL=false
spring.datasource.username=demo
spring.datasource.password=demo
spring.datasource.driverClassName=com.mysql.jdbc.Driver

#セカンダリーDB
secondary.datasource.url=jdbc:mysql://localhost:3306/secondary_db?useSSL=false
secondary.datasource.username=demo
secondary.datasource.password=demo
secondary.datasource.driverClassName=com.mysql.jdbc.Driver

spring.jpa.database=default

通常の通りにSpring bootのmainクラスを作成します。

DemoApplication
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

プライマリーのdataSource、entityManagerとtransactionManagerを定義します。
 ・リポジトリクラスのbasepackage
 ・ドメインクラスのbasepackage

PrimaryDbConfig
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactory"
                       , transactionManagerRef = "transactionManager"
                       , basePackages = { "com.example.demo.primary" })
public class PrimaryDbConfig {

    @Primary
    @Bean(name = "dataSource")
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }

    @Primary
    @Bean(name = "entityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(
            EntityManagerFactoryBuilder builder,
            @Qualifier("dataSource") DataSource dataSource) {
        return builder.dataSource(dataSource).packages("com.example.demo.primary.domain").build();
    }

    @Primary
    @Bean(name = "transactionManager")
    public PlatformTransactionManager transactionManager(
            @Qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }
}

上記と同様にセカンダリーのdataSource、entityManagerとtransactionManagerを定義します。

SecondaryDbConfig
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "secondaryEntityManagerFactory"
                       , transactionManagerRef = "secondaryTransactionManager"
                       , basePackages = {"com.example.demo.secondary" })
public class SecondaryDbConfig {

    @Bean(name = "secondaryDataSource")
    @ConfigurationProperties(prefix = "secondary.datasource")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "secondaryEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory(
            EntityManagerFactoryBuilder builder,
            @Qualifier("secondaryDataSource") DataSource dataSource) {
        return builder.dataSource(dataSource).packages("com.example.demo.secondary.domain").build();
    }

    @Bean(name = "secondaryTransactionManager")
    public PlatformTransactionManager secondaryTransactionManager(
            @Qualifier("secondaryEntityManagerFactory") EntityManagerFactory secondaryEntityManagerFactory) {
        return new JpaTransactionManager(secondaryEntityManagerFactory);
    }
}

それぞれのリポジトリクラスとドメインクラスを作成します。

PrimaryRepository
@Repository
public interface PrimaryRepository extends CrudRepository<Emp, String> {
    public long count();    
}
SecondaryRepository
@Repository
public interface SecondaryRepository extends CrudRepository<Emp2, String> {
    public long count();
}
EmpDomain
@Entity
@Table(name="emp")
public class Emp {

    @Id
    @Column(name="emp_id")
    private String empId;

    @Column(name="dept_id")
    private String deptId;

    ...
}
EmpDomain2
@Entity
@Table(name="emp2")
public class Emp2 {

    @Id
    @Column(name="emp_id")
    private String empId;

    @Column(name="dept_id")
    private String deptId;

    ...

Mybatisと同じの感じてリポジトリクラスを呼び出します。

    @Autowired
    private PrimaryRepository primaryRepository;
    @Autowired
    private SecondaryRepository secondaryRepository;

    ...
    long countPrimary = primaryRepository.selectCountFromPrimary();
    long countSecondary = secondaryRepository.selectCountFromSecondary();

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
26
Help us understand the problem. What are the problem?