当前位置:首页 >百科 >基于Spring boot轻松实现一个多数据源框架 它很容易使用和实现

基于Spring boot轻松实现一个多数据源框架 它很容易使用和实现

2024-06-29 06:49:13 [百科] 来源:避面尹邢网

基于Spring boot轻松实现一个多数据源框架

作者:迷路的基于架架构师 数据库 Spring Boot 提供了 Data JPA 的包,允许你使用类似 ORM 的轻松接口连接到 RDMS。它很容易使用和实现,实现数据只需要在 pom.xml 中添加一个条目(如果使用的个多是 Maven,Gradle 则是源框在 build.gradle 文件中)。

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 个注释:

基于Spring boot轻松实现一个多数据源框架 它很容易使用和实现

@SpringBootApplication@EnableJpaRepositories@EnableAutoConfigurationpublic class SpringMainApplication {     public static void main(String[] args) {         SpringApplication.run(SpringMainApplication.class,基于架 args);    }}

最后添加一个数据库连接包,配置数据库连接即可实现与数据库通信。轻松

基于Spring boot轻松实现一个多数据源框架 它很容易使用和实现

接下来,实现数据我们开始配置多数据源连接。个多

基于Spring boot轻松实现一个多数据源框架 它很容易使用和实现

注意:多个数据库应该具有相同的源框驱动程序。无法连接到不同的数据库,如 MySql 和 Postgres SQL 数据库。数据库必须相同。此外,数据库模式必须相同,不同模式的 2 个数据库无法进行连接。

多数据源有哪些应用场景?

1.支持具有相同模式的同一应用程序内的多租户。

2.动态模拟多个环境数据库上的行为 ,而不需要重新启动应用程序。 例如,你可以动态连接到开发数据库或 QA 数据库,而无需重新启动应用程序。

3.支持多个数据库来模拟各种自动化测试场景。不同数据库可能具有不同的配置和静态信息,意味着你可以用一个自动化测试脚本覆盖多个测试用例。

4.在同一个应用程序中支持多个组织。根据用户登录,可以动态决定他们的数据应进入哪个组织的数据库。

5.一次性为多个数据库插入数据。例如,你有一个从脚本创建数据的批处理作业,你可以一次性连接到多个数据库,并对所有这些数据库运行脚本,而无需指向不同的应用程序或重新启动服务器来执行此操作。

多数据源示意图如下:

第一步:添加 pom 依赖

<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/dbname1app.datasource.db1.username=postgresapp.datasource.db1.password=passwordapp.datasource.db2.jdbc-url=jdbc:postgresql://db2.com:5432/dbname2app.datasource.db2.username=postgresapp.datasource.db2.password=passwordapp.datasource.db3.jdbc-url=jdbc:postgresql://db3.com:5432/dbname3app.datasource.db3.username=postgresapp.datasource.db3.password=password

这是 3 个独立的 PostgresSQL 实例,具有相同的模式但具有不同的数据。

第三步:添加多数据库配置。

首先,在 Spring 应用程序主文件中添加注解:

@SpringBootApplication@EnableJpaRepositories@EnableAutoConfigurationpublic 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<ClientNames> 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();    }}

ClientNames枚举类如下:

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);    }}

ClientMasterService实现如下:

@Servicepublic 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 基础代码:

@Repositorypublic interface ClientMasterRepository extends JpaRepository<Entity1, String> {     Entity1 findByEntity1Name(String name);}

Entity1 类如下:

@Entity@Table(name = "entity1")@Getter@Setterpublic class Entity1 implements Serializable {   @Id  @Column(name = "id", nullable = false)  private Integer id;      @Column(name = "entity1Name")  private String entity1Name; }

这样就完成了整个多数据源的配置!!!

总结

如果你有多租户需求,或者多环境测试需求等,可以自己尝试编写一个多数据源框架,也可以引入第三方库来解决此需求。

责任编辑:华轩 来源: 今日头条 数据源数据库

(责任编辑:休闲)

    推荐文章
    • 机构逐鹿基金代销 8家商业银行入围十强

      机构逐鹿基金代销 8家商业银行入围十强在群雄逐鹿基金代销市场的当前,商业银行仍然是主力军。中国基金业协会近日发布的2021年三季度基金代销机构公募基金保有规模数据显示,银行在股票+混合公募基金、非货币市场公募基金保有规模中的比例仍超五成。 ...[详细]
    • 陈皮是用哪种桔子做的

      陈皮是用哪种桔子做的什么品种的橘子适合做陈皮-九州醉餐饮网茶枝柑,瓯柑,柑橘,蕉柑,四会柑,红橘。做陈皮的橘子要选用成熟的橘子的皮来晾晒,因为未成熟的橘子做的叫做青皮,青皮和陈皮的功效是不一样的。在晾晒。想自己在家晒陈皮 ...[详细]
    • 如何释放被子的静电

      如何释放被子的静电被子起静电怎么办?被子全是静电可以采用以下方法进行处理。1.将有静电的被子放置在太阳下晒1-3小时。2.用喷雾在被子上撒上适量的水,后用加热毯,加热40-60分钟。3.将被子用清。被子上有静电,怎么弄 ...[详细]
    • 牛奶加水可以喝吗

      牛奶加水可以喝吗牛奶兑水给宝宝喝可以吗?你好!根据你的描述考虑牛奶可以兑水给孩子喝的,建议给孩子喝奶最好喝纯牛奶添加剂比核桃奶添加剂比较少纯牛奶可以加水吗?回答你的问题,纯牛奶可以加水,但是不建议你加的太多。如果纯牛 ...[详细]
    • 花呗升级信用购是什么意思 花呗新升级千万别点是为什么?

      花呗升级信用购是什么意思 花呗新升级千万别点是为什么?花呗很多人都使用过,并且有不少人页面提示花呗服务升级。而因为花呗开启了品牌隔离工作,升级后的花呗页面会出现信用购。那么花呗升级信用购是什么意思?花呗新升级千万别点是为什么?这里就和大家来讨论下这个话题 ...[详细]
    • 滚出中国什么梗

      滚出中国什么梗为什么让浙江滚出中国?新浪微博,有个叫“范晓沐”的的人在微博上发表热门话题:#浙江滚出中国#说的是,浙江这次的台风让浙江人自救说浙江人都那么富,那么有钱,有钱人多...d3玩家滚出wow是什么梗?一个 ...[详细]
    • 吃新鲜龙眼有什么好处

      吃新鲜龙眼有什么好处吃鲜桂圆有什么好处指导意见:龙眼有补心安神、养血益脾之效,但龙眼甘温大热,一切阴虚内热体质及患热性疾病者均不宜食用。祝好新鲜龙眼的功效与作用是什么?龙眼就是我们平常所说的桂圆,龙眼是一种比较甜的水果, ...[详细]
    • 梅西标志图片

      梅西标志图片前言:梅西图片你的要求真是太难达到了!!!!!这是我找到的,虽然没有特别符合的,但我也尽力了http://tieba.baidu.com/f?kz=180246727http://www.5aqq.c ...[详细]
    • 航天科技集团研制大气环境监测卫星大气一号上线 高精度监测能力提升

      航天科技集团研制大气环境监测卫星大气一号上线 高精度监测能力提升4月16日,长四丙火箭在太原卫星发射中心成功发射升空。这一次,搭乘金牌“太空专列”的是大气环境监测卫星(简称大气一号),是世界首颗二氧化碳激光探测卫星。在705公里的太阳同步轨 ...[详细]
    • 易唱网

      易唱网前言:答:《零几年听的情歌》歌词:写一首十几岁听的情歌,可惜我没在那个时候遇见你否则我努力活到百岁后,就刚好爱你一整个世纪被我抓在手心里的秘密,总有一天会亲手交给你再行不通我就要穿越回过去,刚好爱你一 ...[详细]
    热点阅读