Spring boot Spring boot读写拆分/主-从/多个数据库

Spring boot Spring boot读写拆分/主-从/多个数据库,spring-boot,spring-data-jpa,Spring Boot,Spring Data Jpa,我正在关注这个链接 我已经实现了代码,但我的两个服务功能仍然使用相同的数据库(一个标记为primary) 服务等级 public class TableService{ @Autowired private Table1Repo t1Repo; @Transactional(readOnly = false) public void saveTable1(Table1 t,int a, Table1 t2){ try{

我正在关注这个链接

我已经实现了代码,但我的两个服务功能仍然使用相同的数据库(一个标记为primary)

服务等级

public class TableService{

    @Autowired
    private Table1Repo t1Repo;
    @Transactional(readOnly = false)
    public void saveTable1(Table1 t,int a, Table1 t2){
            try{
                t1Repo.save(t2);
            }
            catch(Exception e){
                System.out.println("Inside");
            }

    }

    @Transactional(readOnly = true)
    public Table1 getTable(int id){
        return t1Repo.findOne(id);
    }


}
然后添加了两个类(从链接)

复制路由数据源

public class ReplicationRoutingDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        String dataSourceType = TransactionSynchronizationManager.isCurrentTransactionReadOnly() ? "read" : "write";
        return dataSourceType;
    }
}
使用路由数据源配置

@Configuration
public class WithRoutingDataSourceConfig {

    /*@Bean(destroyMethod = "shutdown")*/
    @Bean
    @Primary
    @ConfigurationProperties(prefix="datasource.primary")
    public DataSource writeDataSource() {
       /* EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
                .setName("routingWriteDb")
                .setType(EmbeddedDatabaseType.H2)
                .setScriptEncoding("UTF-8")
                .addScript("classpath:/writedb.sql");
        return builder.build();*/
        return DataSourceBuilder.create().build();
    }

/*    @Bean(destroyMethod = "shutdown")*/
    @Bean
    @ConfigurationProperties(prefix="datasource.secondary")
    public DataSource readDataSource() {
        /*EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
                .setName("routingReadDb")
                .setType(EmbeddedDatabaseType.H2)
                .setScriptEncoding("UTF-8")
                .addScript("classpath:/readdb.sql");
        return builder.build();*/
        return DataSourceBuilder.create().build();
    }

    /**
     * {@link org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource}는
     * {@link org.springframework.beans.factory.InitializingBean}을 구현하므로,
     * 명시적으로 afterPropertiesSet()메소드를 호출하거나
     * 별도 @Bean으로 만들어 Spring Life Cycle을 타도록 해야 한다.
     */
    @Bean
    public DataSource routingDataSource(@Qualifier("writeDataSource") DataSource writeDataSource, @Qualifier("readDataSource") DataSource readDataSource) {
        ReplicationRoutingDataSource routingDataSource = new ReplicationRoutingDataSource();

        Map<Object, Object> dataSourceMap = new HashMap<Object, Object>();
        dataSourceMap.put("write", writeDataSource);
        dataSourceMap.put("read", readDataSource);
        routingDataSource.setTargetDataSources(dataSourceMap);
        routingDataSource.setDefaultTargetDataSource(writeDataSource);

        return routingDataSource;
    }

    /**
     * {@link org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy}로 감싸서
     * 트랜잭션 동기화가 이루어진 뒤에 실제 커넥션을 확보하도록 해준다.
     *
     * @param routingDataSource
     * @return
     */
    @Bean
    public DataSource dataSource(@Qualifier("routingDataSource") DataSource routingDataSource) {
        return new LazyConnectionDataSourceProxy(routingDataSource);
    }
}
存储库

public interface Table1Repo extends JpaRepository<Table1, Integer>{}

我是你提到的链接的作者

您在Table1Reporto中使用哪种数据源

您必须向JDBC调用注入特定的bean“数据源”

我猜
@Primary
“writeDataSource”被注入到您的存储库中


尝试将
@Primary
更改为“dataSource”,或找到将“dataSource”注入存储库的方法。

您也可以通过以下方式尝试:

下面是github中的源代码:

下面的链接解释了如何拥有多个数据源

DB1(写入):

DB2(读取):


错误是什么?没有错误。它只是使用主数据库进行读写(对于我的两个服务功能),但我希望它使用diff DB进行基于注释的读写。我遇到了与您完全相同的问题(包括我将@primary放在LazyConnectionDataSourceProxy上的第一个周期。你能解释一下你的解决方案吗?我们为什么应该把这些bean放在哪里?我试着把它们放在与数据源相同的类中,但它不起作用。如果我将@primary添加到数据源中,这会使我错误地理解一些bean的依赖关系。)应用程序上下文中的bean形成一个循环:org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration┌─────┐ | 在类路径资源[com/example/WithRoutingDataSourceConfig.class]中定义的数据源↑ ↓ | 在类路径资源[com/example/WithRoutingDataSourceConfig.class]中定义的routingDataSource↑ ↓ | 在类路径资源[com/example/WithRoutingDataSourceConfig.class]中定义的writeDataSource↑ ↓ | DataSourceInitializationeral虽然我已经通过上面的代码和添加一个配置类使代码正常工作。我已经更新了我的问题,请您检查它是否正确。此外,我的Table1Reporto将同时使用读写数据源。我相信您的第二个解决方案是可以的。但我仍然不理解为什么数据源配置是循环的。这可能是SpringBoot JPA自动配置的问题。我在Spring中使用此解决方案时没有任何问题。KwonNam:我在一个项目中工作&我有一个要求,我需要两个不同的数据库&我希望对这两个数据库进行读/写拆分?那么我是否要更改代码?如果我想在单个流中使用读写(调用),我该怎么做?既然determineLookUpKey只被调用了一次而不是更多,现在发生了什么?
public interface Table1Repo extends JpaRepository<Table1, Integer>{}
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages="com.example")
public class ReplicationDataSourceApplicationConfig {

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier("dataSource") DataSource dataSource) {
        LocalContainerEntityManagerFactoryBean emfb = new LocalContainerEntityManagerFactoryBean();
        emfb.setDataSource(dataSource);
        emfb.setPackagesToScan("com.example");        
        HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
        emfb.setJpaVendorAdapter(jpaVendorAdapter);

        return emfb;
    }

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory);
        return transactionManager;
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslationPostProcessor() {
        return new PersistenceExceptionTranslationPostProcessor();
    }
}
@Configuration
@ConfigurationProperties("spring.datasource-write")
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "entityManagerFactoryWrite",
        transactionManagerRef = "transactionManagerWrite",
        basePackages = {"com.ehsaniara.multidatasource.repository.writeRepository"}
)
public class DataSourceConfigWrite extends HikariConfig {

    public final static String PERSISTENCE_UNIT_NAME = "write";

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

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryWrite(
            final HikariDataSource dataSourceWrite) {

        return new LocalContainerEntityManagerFactoryBean() {{
            setDataSource(dataSourceWrite);
            setPersistenceProviderClass(HibernatePersistenceProvider.class);
            setPersistenceUnitName(PERSISTENCE_UNIT_NAME);
            setPackagesToScan(MODEL_PACKAGE);
            setJpaProperties(JPA_PROPERTIES);
        }};
    }

    @Bean
    public PlatformTransactionManager transactionManagerWrite(EntityManagerFactory entityManagerFactoryWrite) {
        return new JpaTransactionManager(entityManagerFactoryWrite);
    }
}
@Configuration
@ConfigurationProperties("spring.datasource-read")
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "entityManagerFactoryRead",
        transactionManagerRef = "transactionManagerRead",
        basePackages = {"com.ehsaniara.multidatasource.repository.readRepository"}
)
public class DataSourceConfigRead extends HikariConfig {

    public final static String PERSISTENCE_UNIT_NAME = "read";


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

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryRead(
            final HikariDataSource dataSourceRead) {

        return new LocalContainerEntityManagerFactoryBean() {{
            setDataSource(dataSourceRead);
            setPersistenceProviderClass(HibernatePersistenceProvider.class);
            setPersistenceUnitName(PERSISTENCE_UNIT_NAME);
            setPackagesToScan(MODEL_PACKAGE);
            setJpaProperties(JPA_PROPERTIES);
        }};
    }

    @Bean
    public PlatformTransactionManager transactionManagerRead(EntityManagerFactory entityManagerFactoryRead) {
        return new JpaTransactionManager(entityManagerFactoryRead);
    }
}