Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

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();
KevinFQ
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした