如何在Spring Boot和JPA中配置和使用多数据源路由?在 DB2 中未创建任何表,保存不适用于 DB1

How to Configure and Use Multi-DataSource Routing with Spring Boot and JPA? No table is getting created in DB2 save not working forDB1

提问人:Supriya_21 提问时间:11/11/2023 更新时间:11/11/2023 访问量:35

问:

我正在开发一个Spring Boot应用程序,我需要根据某些条件路由到不同的数据源。具体来说,我希望在保存 StudentEntity 实例时路由到不同的数据库,具体取决于给定条件。以下是我目前的设置:

  @Override
    public StudentEntity saveStudent(StudentEntity studentEntity,String db) {
        StudentEntity save = null;
        if(db.equals("DB1")) {
            DBContextHolder.setCurrentDb(ClientNames.DB1);
             save = studentRepository.save(studentEntity);
        }
        else{
            DBContextHolder.setCurrentDb(ClientNames.DB2);
            save = studentRepository.save(studentEntity);
        }
        return save;
    }

数据库配置

@Configuration
@PropertySource({"classpath:application.properties"})
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "multiEntityManager",
        transactionManagerRef = "multiTransactionManager")
@EntityScan("com.demo.MyDemo.model")
public class DatabaseConfiguration {
    private final String PACKAGE_SCAN = "com.demo.MyDemo.model";

    @Primary
    @Bean(name = "db1DataSource")
    @ConfigurationProperties("spring.datasource")
    public DataSource db1DataSource() {
        return DataSourceBuilder.create().type(HikariDataSource.class).build();
    }

    //connection objects for the remaining 2 databases

    @Bean(name = "db2DataSource")
    @ConfigurationProperties("app.datasource.db2")

    public DataSource db2DataSource() {
        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());

        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 = "transactionManager")
    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;
    }

    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.MySQL5InnoDBDialect");
        properties.put("hibernate.hbm2ddl.auto", "create");
        properties.put("hibernate.id.new_generator_mappings", false);
        properties.put("hibernate.jdbc.lob.non_contextual_creation", true);
        return properties;
    }


}

application.properties

spring.datasource.jdbc-url= jdbc:mysql://localhost:3306/mydemo
spring.datasource.username=root
spring.datasource.password=root

app.datasource.db2.jdbc-url= jdbc:mysql://localhost:3306/mydemolocal
app.datasource.db2.username=root
app.datasource.db2.password=root
app.datasource.db2.hibernate.ddl-auto=create
app.datasource.db2.jpa.generate-ddl=true
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=update

服务实现

  @Override
    public StudentEntity saveStudent(StudentEntity studentEntity,String db) {
        StudentEntity save = null;
        if(db.equals("DB1")) {
            DBContextHolder.setCurrentDb(ClientNames.DB1);
             save = studentRepository.save(studentEntity);
        }
        else{
            DBContextHolder.setCurrentDb(ClientNames.DB2);
            save = studentRepository.save(studentEntity);
        }
        return save;
    }

我希望在实现方法中根据条件将数据保存在数据库的任何一个 on 中

java mysql spring-boot 休眠 jpa

评论

0赞 Harry Coder 11/11/2023
此链接可能会有所帮助: baeldung.com/multitenancy-with-spring-data-jpa
0赞 Supriya_21 11/11/2023
感谢您的链接,我一定会尝试这种方法,而如果有人对我的代码有任何想法,请提供帮助
0赞 Chris 11/11/2023
该方法已关闭,因为您正在将数据库上下文从假定只有一个数据库 - DDL 在 JPA 启动时执行,并且不知道您的第二个数据库上下文。您需要在每个数据库之上有一个持久性单元,并在它们之间切换。或者,您需要自己的启动逻辑来遍历每个数据库,并通过 JPA Persistence.generateSchema 方法手动创建数据库。不过,我不确定在保存到 db1 时您的代码出了什么问题 - 您必须检查事务的行为方式。

答: 暂无答案