Spring Boot多数据源配置详细说明

背景

在项目中有时候需要同时连接多个数据库,由于一般数据库的连接都是通过数据源连接池去连接的,所以该问题就是多数据源的配置问题。下面通过Spring Boot Jpa框架说明多数据源的配置方式及要点。

第一步创建DataSource

其实DataSource的创建并不复杂,首先准备两个数据库test1、test2,他们分别包含t_product、t_user
在这里插入图片描述
application.properties配置如下

app.datasource.test1.jdbc-url= jdbc:mysql://127.0.0.1:3306/test1
app.datasource.test1.username= root
app.datasource.test1.password=

app.datasource.test2.jdbc-url= jdbc:mysql://127.0.0.1:3306/test2
app.datasource.test2.username= root
app.datasource.test2.password=

由于是多数据源而数据源又是为jpa服务的,所以在dao层的包结构下将不同数据库的实体分开放置,这样的作用后面再说
在这里插入图片描述

@Data
@Entity
@Table(name = "t_product")
public class ProductDO {
    @Id
    @GeneratedValue
    private Long id;
    private String productName;
}

public interface ProductRepository extends JpaRepository<ProductDO, Long> {}

@Data
@Entity
@Table(name = "t_user")
public class UserDO {
    @Id
    @GeneratedValue
    private Long id;
    private String userName;
}

public interface UserRepository extends JpaRepository<UserDO,Long> {}

Test1Config通过@ConfigurationProperties注解,自动读取application.properties中app.datasource.test1开头的配置项注入到该类中,由于该类是继承的HikariConfig,所以实际是注入到了HikariConfig

@Configuration
@ConfigurationProperties("app.datasource.test1")
public class Test1Config extends HikariConfig {

    @Bean
    public DataSource test1DataSource(){
        return new HikariDataSource(this);
    }

}

查看HikariConfig的代码里面就有相关的属性
在这里插入图片描述
Test2Config同理,需要注意将test1替换为test2。这时启动项目就能看到两个DataSource创建了

2019-01-21 09:59:43.554  INFO 63713 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2019-01-21 09:59:43.816  INFO 63713 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2019-01-21 09:59:43.827  INFO 63713 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Starting...
2019-01-21 09:59:43.835  INFO 63713 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Start completed.

第二步创建EntityManagerFactory

在jdbc中有数据源就可以工作了,但在Jpa中还需要EntityManagerFactory,那么第二步就是创建EntityManagerFactory,关于EntityManagerFactory的相关概念可以看之前的博客Spring Data之EntityManagerFactory创建及源码分析

@Configuration
@ConfigurationProperties("app.datasource.test1")
public class Test1Config extends HikariConfig {

    @Bean
    public DataSource test1DataSource(){
        return new HikariDataSource(this);
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean test1EntityManagerFactory() {
        HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
        jpaVendorAdapter.setGenerateDdl(false);
        jpaVendorAdapter.setShowSql(true);

        LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
        //设置数据源
        factoryBean.setDataSource(test1DataSource());
        //设置jpa相关参数
        factoryBean.setJpaVendorAdapter(jpaVendorAdapter);
        //设置该EntityManagerFactory需要扫描的包路径
        //这里就是将dao层的包结构下将不同数据库的实体分开放置的好处
        //意思是该包下的实体操作都是有该EntityManagerFactory处理
        factoryBean.setPackagesToScan(Test1Config.class.getPackage().getName());
        factoryBean.setPersistenceUnitName("test1");

        HashMap<String, Object> properties = new HashMap<>();
        properties.put("hibernate.physical_naming_strategy","org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");
        factoryBean.setJpaPropertyMap(properties);

        return factoryBean;
    }

}

其中hibernate.physical_naming_strategy:org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy设置的作用是告知jpa实体与sql的映射使用驼峰命名法,即java代码中的productName属性在生成sql时将转换为product_name

第三步创建TransactionManager

在jpa中事务是通过EntityManagerFactory获取的,因为是不同的EntityManagerFactory所以也要创建不同的TransactionManager

@Bean
PlatformTransactionManager test1TransactionManager() {
    return new JpaTransactionManager(test1EntityManagerFactory().getObject());
}

第四步开启JPA

在Sping Boot中要启用JPA除了引用jar

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

还需要通过@EnableJpaRepositories注解开启JPA相关的初始化,由于这里我们是手动创建的EntityManagerFactoryTransactionManager,所以需要手动设置@EnableJpaRepositories的参数,以下的完整的代码

@Configuration
@ConfigurationProperties("app.datasource.test1")
@EnableJpaRepositories(
        entityManagerFactoryRef = "test1EntityManagerFactory",
        transactionManagerRef = "test1TransactionManager")
public class Test1Config extends HikariConfig {

    @Bean
    public DataSource test1DataSource(){
        return new HikariDataSource(this);
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean test1EntityManagerFactory() {
        HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
        jpaVendorAdapter.setGenerateDdl(true);
        jpaVendorAdapter.setShowSql(true);

        LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
        factoryBean.setDataSource(test1DataSource());
        factoryBean.setJpaVendorAdapter(jpaVendorAdapter);
        factoryBean.setPackagesToScan(Test1Config.class.getPackage().getName());
        factoryBean.setPersistenceUnitName("test1");

        HashMap<String, Object> properties = new HashMap<>();
        properties.put("hibernate.physical_naming_strategy","org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");
        factoryBean.setJpaPropertyMap(properties);

        return factoryBean;
    }

    @Bean
    PlatformTransactionManager test1TransactionManager() {
        return new JpaTransactionManager(test1EntityManagerFactory().getObject());
    }
}

启动项目可以看到控制台输出,创建了两个数据源以及test1、test2的PersistenceUnitInfo

2019-01-21 10:24:23.416  INFO 63865 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2019-01-21 10:24:23.776  INFO 63865 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2019-01-21 10:24:23.799  INFO 63865 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [
	name: test1
	...]
2019-01-21 10:24:23.840  INFO 63865 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate Core {5.3.7.Final}
2019-01-21 10:24:23.841  INFO 63865 --- [           main] org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found
2019-01-21 10:24:23.925  INFO 63865 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.0.4.Final}
2019-01-21 10:24:24.018  INFO 63865 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.MySQL57Dialect
2019-01-21 10:24:24.162  INFO 63865 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'test1'
2019-01-21 10:24:24.173  INFO 63865 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Starting...
2019-01-21 10:24:24.180  INFO 63865 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Start completed.
2019-01-21 10:24:24.182  INFO 63865 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [
	name: test2
	...]
2019-01-21 10:24:24.185  INFO 63865 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.MySQL57Dialect
2019-01-21 10:24:24.195  INFO 63865 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'test2'

验证

测试一下分别往两个表插入一条数据

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {

    @Autowired
    private ProductRepository productRepository;
    @Autowired
    private UserRepository userRepository;

	@Test
	public void test() {
        ProductDO productDO = new ProductDO();
        productDO.setProductName("苹果");
        productRepository.save(productDO);

        UserDO userDO = new UserDO();
        userDO.setUserName("张三");
        userRepository.save(userDO);
	}

}

可以看到数据被正确插入对应的数据库
在这里插入图片描述
在这里插入图片描述

总结

网上有很多创建多数据源的文章,但都不尽相同。不过只要明白了套路(步骤)就可以变化写法定制自己需要的多数据源形式。

猜你喜欢

转载自blog.csdn.net/f4761/article/details/86568701