项目的需求描述:我有多个数据库,每一个数据库分属于不同的厂家,但是数据库结构是相同的,我要通过切换不同的数据库,使应用服务器连接不通的数据库,来展示不同的数据。假如说,每一个数据库搭配一套一模一样的应用程序和服务器,这当然可以满足需求,但是我只有一台服务器,一台服务器上有多个数据库,我总不能再tomcat中部署多套应用程序,然后根据不同的url,使用不同的应用程序进行服务吧,感觉有点奇怪。
参考文章中,有对处理多个数据库的读写的策略进行了描述:
(1) 多套数据源:即针对一个数据库建立一套数据处理逻辑,每套数据库都包括数据源配置、会话工厂( sessionFactory )、连接、SQL 操作、实体。各套数据库相互独立。
(2) 动态数据源:确定数量的多个数据源共用一个会话工厂,根据条件动态选取数据源进行连接、SQL 操作。
(3) 参数化变更数据源:根据参数添加数据源,并进行数据源切换,数据源数量不确定。通常用于对多个数据库的管理工作。
应用场景:
(1) 数据库高性能场景:主从,包括一主一从,一主多从等,在主库进行增删改操作,在从库进行读操作。
(2) 数据库高可用场景:主备,包括一往一备,多主多备等,在数据库无法访问时可以切换。
(3) 同构或异构数据的业务处理:需要处理的数据存储在不同的数据库中,包括同构(如都是 MySQL ),异构(如一个MySQL ,另外是 PG 或者 Oracle )。
下面以配置sqlserver和postgresql为例子,结合参考文章1,并进行部分修改,讲解如何配置多个数据源
1.添加依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.1.RELEASE</version> <relativePath/> </parent>
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>
<dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> </dependency>
<dependency> <groupId>com.microsoft.sqlserver</groupId> <artifactId>sqljdbc4</artifactId> <version>4.0</version> </dependency> </dependencies>
|
2.编辑application.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| spring: datasource: first: driver-class-name: org.postgresql.Driver jdbc-url: jdbc:postgresql://localhost:5432/hdxs username: postgres password: 1q2w3e4r connection-timeout: 20000 maximum-pool-size: 5 second: driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver jdbc-url: jdbc:sqlserver://xxx:xxx;DatabaseName=xxx username: xxx password: xxx connection-timeout: 20000 maximum-pool-size: 5 jpa: hibernate: naming: implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl show-sql: true
|
3.编写实体和Repository
我这里有两个数据源,就分别对每一个数据源编写相应的实体类以及Repository,这里我就不贴源码了,贴个目录结构吧,因为包名,在以后还有用的着的地方
4.编写DataSourceConfiguration
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| @Configuration public class DataSourceConfiguration {
@Bean(name = "dataSourceFirst") @Primary @ConfigurationProperties(prefix = "spring.datasource.first") public DataSource dataSourceFirst() { return DataSourceBuilder.create().build(); }
@Bean(name = "dataSourceSecond") @ConfigurationProperties(prefix = "spring.datasource.second") public DataSource dataSourceSecond() { return DataSourceBuilder.create().build(); } }
|
5.编写第一个数据源配置
这里的basePackages,和packages等,要和你自己的entity以及reposities包的路径相同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| @Configuration @EntityScan(basePackages = "com.proheng.gis.postgresqlEntity")
@EnableJpaRepositories( basePackages = "com.proheng.gis.postgresqlReposities", entityManagerFactoryRef = "firstEntityManagerFactoryBean", transactionManagerRef = "firstTransactionManager") @EnableTransactionManagement public class JpaFirstConfiguration {
@Autowired @Qualifier("dataSourceFirst") private DataSource dataSource;
@Autowired private JpaProperties jpaProperties;
@Autowired private EntityManagerFactoryBuilder factoryBuilder;
@Bean(name = "firstEntityManagerFactoryBean") @Primary public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() { return factoryBuilder.dataSource(dataSource) .properties(getVendorProperties(dataSource)) .packages("com.proheng.gis.postgresqlEntity") .persistenceUnit("firstPersistenceUnit") .build(); }
@Autowired private HibernateProperties hibernateProperties;
private Map<String, Object> getVendorProperties(DataSource dataSource) { return hibernateProperties.determineHibernateProperties( jpaProperties.getProperties(), new HibernateSettings()); }
@Bean(name = "firstEntityManager") @Primary public EntityManager entityManager() { return entityManagerFactoryBean().getObject().createEntityManager(); }
@Bean(name = "firstTransactionManager") @Primary public JpaTransactionManager transactionManager() { JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(); jpaTransactionManager.setEntityManagerFactory(entityManagerFactoryBean().getObject()); return jpaTransactionManager; } }
|
6.编写第二个数据源配置
方法同上,也要主要相应的包名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| @Configuration @EntityScan(basePackages = "com.proheng.gis.sqlserverEntity")
@EnableJpaRepositories( basePackages = "com.proheng.gis.sqlserverReposities", entityManagerFactoryRef = "secondEntityManagerFactoryBean", transactionManagerRef = "secondTransactionManager") @EnableTransactionManagement public class JpaSecondConfiguration {
@Autowired @Qualifier("dataSourceSecond") private DataSource dataSource;
@Autowired private JpaProperties jpaProperties;
@Autowired private EntityManagerFactoryBuilder factoryBuilder;
@Bean(name = "secondEntityManagerFactoryBean") public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() { return factoryBuilder.dataSource(dataSource) .properties(getVendorProperties(dataSource)) .packages("com.proheng.gis.sqlserverEntity") .persistenceUnit("secondPersistenceUnit") .build(); } @Autowired private HibernateProperties hibernateProperties;
private Map<String, Object> getVendorProperties(DataSource dataSource) { return hibernateProperties.determineHibernateProperties( jpaProperties.getProperties(), new HibernateSettings()); }
@Bean(name = "secondEntityManager") public EntityManager entityManager() { return entityManagerFactoryBean().getObject().createEntityManager(); }
@Bean(name = "secondTransactionManager") public JpaTransactionManager transactionManager() { JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(); jpaTransactionManager.setEntityManagerFactory(entityManagerFactoryBean().getObject()); return jpaTransactionManager; } }
|
其中getVendorProperties方法,可以通过下面的形式,为每一个数据源配置不同的属性,比如方言:
1 2 3 4 5 6 7
| private Map<String, Object> getVendorProperties(DataSource dataSource) { Map<String,String> properties=new HashMap<>(); properties.put("hibernate.temp.use_jdbc_metadata_defaults","false"); properties.put("hibernate.dialect","org.hibernate.dialect.SQLServer2012Dialect"); return hibernateProperties.determineHibernateProperties( properties, new HibernateSettings()); }
|
这样就配置了两个不同的数据源了,我在想,其实是不是还可以配置三个,四个数据源,只要有数据源配置类就好了。