Spring Boot 提供了 Data JPA 的包,允许你使用类似 ORM 的接口连接到 RDMS。它很容易使用和实现,只需要在 pom.xml 中添加一个条目(如果使用的是 Maven,Gradle 则是在 build.gradle 文件中)。
- <dependencies>
- <!-- Spring boot 依赖 -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-jpa</artifactId>
- </dependency>
- </dependencies>
在Main Spring Application类中添加 2 个注释:
- @SpringBootApplication
- @EnableJpaRepositories
- @EnableAutoConfiguration
- public class SpringMainApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(SpringMainApplication.class, args);
- }
- }
最后添加一个数据库连接包,配置数据库连接即可实现与数据库通信。
接下来,我们开始配置多数据源连接。
注意:多个数据库应该具有相同的驱动程序。无法连接到不同的数据库,如 MySql 和 Postgres SQL 数据库。数据库必须相同。此外,数据库模式必须相同,不同模式的 2 个数据库无法进行连接。
1.支持具有相同模式的同一应用程序内的多租户。
2.动态模拟多个环境数据库上的行为 ,而不需要重新启动应用程序。 例如,你可以动态连接到开发数据库或 QA 数据库,而无需重新启动应用程序。
3.支持多个数据库来模拟各种自动化测试场景。不同数据库可能具有不同的配置和静态信息,意味着你可以用一个自动化测试脚本覆盖多个测试用例。
4.在同一个应用程序中支持多个组织。根据用户登录,可以动态决定他们的数据应进入哪个组织的数据库。
5.一次性为多个数据库插入数据。例如,你有一个从脚本创建数据的批处理作业,你可以一次性连接到多个数据库,并对所有这些数据库运行脚本,而无需指向不同的应用程序或重新启动服务器来执行此操作。
多数据源示意图如下:

- <dependencies>
- <!-- Spring boot dependencies -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-actuator</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-devtools</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-jpa</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
-
- <!-- Swagger dependencies -->
- <dependency>
- <groupId>io.springfox</groupId>
- <artifactId>springfox-swagger2</artifactId>
- <version>2.9.2</version>
- </dependency>
- <dependency>
- <groupId>io.springfox</groupId>
- <artifactId>springfox-swagger-ui</artifactId>
- <version>2.9.2</version>
- </dependency>
-
- <!-- lombok dependency -->
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <version>1.18.12</version>
- <scope>provided</scope>
- </dependency>
-
- <!-- Database dependency -->
- <dependency>
- <groupId>org.postgresql</groupId>
- <artifactId>postgresql</artifactId>
- </dependency>
-
-
- <!-- test dependencies -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- <exclusions>
- <exclusion>
- <groupId>org.junit.vintage</groupId>
- <artifactId>junit-vintage-engine</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- </dependencies>
-
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-parent</artifactId>
- <version>${spring-cloud-dependencies.version}</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-gcp-dependencies</artifactId>
- <version>${project.version}</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
- </dependencies>
- </dependencyManagement>
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- </plugin>
- </plugins>
- </build>
- app.datasource.db1.jdbc-url=jdbc:postgresql://db1.com:5432/dbname1
- app.datasource.db1.username=postgres
- app.datasource.db1.password=password
-
- app.datasource.db2.jdbc-url=jdbc:postgresql://db2.com:5432/dbname2
- app.datasource.db2.username=postgres
- app.datasource.db2.password=password
-
- app.datasource.db3.jdbc-url=jdbc:postgresql://db3.com:5432/dbname3
- app.datasource.db3.username=postgres
- app.datasource.db3.password=password
这是 3 个独立的 PostgresSQL 实例,具有相同的模式但具有不同的数据。
首先,在 Spring 应用程序主文件中添加注解:
- @SpringBootApplication
- @EnableJpaRepositories
- @EnableAutoConfiguration
- public class MultidatabaseApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(MultidatabaseApplication.class, args);
- }
- }
添加配置类:
- @Configuration
- @EnableTransactionManagement
- @EnableJpaRepositories(
- entityManagerFactoryRef = "multiEntityManager",
- transactionManagerRef = "multiTransactionManager")
- @EntityScan("com.sample.client.repositories.dto.entity")
- public class DatabaseConfiguration {
- //添加 JPA 实体路径
- private final String PACKAGE_SCAN = "com.sample.client.repositories.dto.entity";
-
- // 将db1设置为主数据库
- @Primary
- @Bean(name = "db1DataSource")
- @ConfigurationProperties("app.datasource.db1")
- public DataSource db1DataSource() {
- return DataSourceBuilder.create().type(HikariDataSource.class).build();
- }
-
- //db2连接数据源注入
- @Bean(name = "db2DataSource")
- @ConfigurationProperties("app.datasource.db2")
- public DataSource db2DataSource() {
- return DataSourceBuilder.create().type(HikariDataSource.class).build();
- }
- //db3连接数据源注入
- @Bean(name = "db3DataSource")
- @ConfigurationProperties("app.datasource.db3")
- public DataSource db3DataSource() {
- return DataSourceBuilder.create().type(HikariDataSource.class).build();
- }
-
- //多数据源配置
- @Bean(name = "multiRoutingDataSource")
- public DataSource multiRoutingDataSource() {
- Map<Object, Object> targetDataSources = new HashMap<>();
- targetDataSources.put(ClientNames.DB1, db1DataSource());
- targetDataSources.put(ClientNames.DB2, db2DataSource());
- targetDataSources.put(ClientNames.DB3, db3DataSource());
- MultiRoutingDataSource multiRoutingDataSource
- = new MultiRoutingDataSource();
- multiRoutingDataSource.setDefaultTargetDataSource(db1DataSource());
- multiRoutingDataSource.setTargetDataSources(targetDataSources);
- return multiRoutingDataSource;
- }
-
- //多实体配置代码
- @Bean(name = "multiEntityManager")
- public LocalContainerEntityManagerFactoryBean multiEntityManager() {
- LocalContainerEntityManagerFactoryBean em
- = new LocalContainerEntityManagerFactoryBean();
- em.setDataSource(multiRoutingDataSource());
- em.setPackagesToScan(PACKAGE_SCAN);
- HibernateJpaVendorAdapter vendorAdapter
- = new HibernateJpaVendorAdapter();
- em.setJpaVendorAdapter(vendorAdapter);
- em.setJpaProperties(hibernateProperties());
- return em;
- }
-
- @Bean(name = "multiTransactionManager")
- public PlatformTransactionManager multiTransactionManager() {
- JpaTransactionManager transactionManager
- = new JpaTransactionManager();
- transactionManager.setEntityManagerFactory(
- multiEntityManager().getObject());
- return transactionManager;
- }
-
- @Primary
- @Bean(name="entityManagerFactory")
- public LocalSessionFactoryBean dbSessionFactory() {
- LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
- sessionFactoryBean.setDataSource(multiRoutingDataSource());
- sessionFactoryBean.setPackagesToScan(PACKAGE_SCAN);
- sessionFactoryBean.setHibernateProperties(hibernateProperties());
- return sessionFactoryBean;
- }
-
- //添加 hibernate 属性
- private Properties hibernateProperties() {
- Properties properties = new Properties();
- properties.put("hibernate.show_sql", true);
- properties.put("hibernate.format_sql", true);
- properties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
- properties.put("hibernate.id.new_generator_mappings", false);
- properties.put("hibernate.jdbc.lob.non_contextual_creation", true);
- return properties;
- }
- }
这样就完成了我们的多数据库配置。
com.sample.client.repositories.dto.entity — 此目录包含 3 个数据库通用的 JPA 实体。
MultiRoutingDataSource类是我们的实际实现,允许我们连接到多个数据库
接下来,我们还需要一个DBContextHolder类来保存数据库引用并在运行时动态更改数据库。
- public class DBContextHolder {
- private static final ThreadLocal
contextHolder = new ThreadLocal<>(); - public static void setCurrentDb(ClientNames dbType) {
- contextHolder.set(dbType);
- }
- public static ClientNames getCurrentDb() {
- return contextHolder.get();
- }
- public static void clear() {
- contextHolder.remove();
- }
- }
- public enum ClientNames {
- DB1, DB2, DB3
- }
接下来我们需要对MultiRoutingDataSource进行重写:
- public class MultiRoutingDataSource extends AbstractRoutingDataSource {
- @Override
- protected Object determineCurrentLookupKey() {
- return DBContextHolder.getCurrentDb();
- }
- }
determineCurrentLookupKey 方法用于决定应用程序应该动态连接到哪个数据库。
好了,我们的配置就完成了。接下来,我们测试下多数据源是否生效:
- @RestController
- @RequestMapping("/client")
- public class ClientDataController {
-
- @Autowired
- private ClientMasterService clientMasterService;
-
- @GetMapping("/{clientdb}")
- public String findFromDatabase(@PathVariable String clientdbName) {
- return clientMasterService.getClientNames(clientdbName);
- }
- }
- @Service
- public class ClientMasterService {
-
- @Autowired
- private ClientMasterRepository clientMasterRepository;
-
- public String getClientNames(String client) {
- switch (client) {
- case "db1":
- DBContextHolder.setCurrentDb(ClientNames.DB1);
- break;
- case "db2":
- DBContextHolder.setCurrentDb(ClientNames.DB2);
- break;
- case "db3":
- DBContextHolder.setCurrentDb(ClientNames.DB3);
- break;
- }
- Entity1 e1 = clientMasterRepository.findByEntity1Name("John Doe");
- if(e1 != null) {
- return "found in database: " + client + " with id " + e1.getId();
- }
- return "found in " + client + " nada!";
- }
- }
ClientMasterService使用DBContextHolder类根据从 Rest 端点传入的数据库名称(db1、db2 或 db3)设置要指向的数据库。
最后,编写 JPA Repository 基础代码:
- @Repository
- public interface ClientMasterRepository extends JpaRepository<Entity1, String> {
- Entity1 findByEntity1Name(String name);
- }
- @Entity
- @Table(name = "entity1")
- @Getter
- @Setter
- public class Entity1 implements Serializable {
- @Id
- @Column(name = "id", nullable = false)
- private Integer id;
-
- @Column(name = "entity1Name")
- private String entity1Name;
- }
这样就完成了整个多数据源的配置!!!
如果你有多租户需求,或者多环境测试需求等,可以自己尝试编写一个多数据源框架,也可以引入第三方库来解决此需求。
这是一款基于SpringBoot+Vue的前后端分离的项目,麻雀虽小,五脏俱全,开箱即用!
JNPF开发平台的前端采用Vue.js,这是一种流行的前端JavaScript框架,用于构建用户界面。Vue.js具有轻量级、可扩展性强和生态系统丰富等特点,被广泛应用于构建单页面应用程序。
后端采用SpringBoot,这是一种基于Java的开源框架,用于简化Spring应用的初始搭建以及开发过程。SpringBoot通过自动配置和约定大于配置的原则,简化了Spring应用的配置和开发。此外,JNPF还采用MyBatis-Plus作为持久层框架,它是一个功能强大的MyBatis扩展,可以大大简化数据库操作的开发。
核心功能:表单引擎、可视化引擎、BI引擎、流程引擎、权限引擎、门户引擎、大屏引擎、接口中心、物联平台
尝试自己开发一个应用!应用地址:https://www.jnpfsoft.com/?csdn