Spring boot Read write Split / Master - Slave / Mu

2019-06-01 00:47发布

I am following this link

https://github.com/kwon37xi/replication-datasource

I have implemented the code But STILL Both my service functions are using the same Database(one which is marked primary)

Service Class

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


}

Then Added two Class(from the link)

ReplicationRoutingDataSource

public class ReplicationRoutingDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        String dataSourceType = TransactionSynchronizationManager.isCurrentTransactionReadOnly() ? "read" : "write";
        return dataSourceType;
    }
}

WithRoutingDataSourceConfig

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

application.prop file

server.port=8089

spring.jpa.show-sql = true
spring.jpa.properties.hibernate.show_sql=true

# Primary DataSource configuration
datasource.primary.url=jdbc:mysql://127.0.0.1:3306/jpa
datasource.primary.username=root
datasource.primary.password=root
# Any of the other Spring supported properties below...

# Secondary DataSource configuration
datasource.secondary.url=jdbc:mysql://127.0.0.1:3306/jpa2
datasource.secondary.username=root
datasource.secondary.password=root

Repository

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

Issue is my both service functions are using the primary Database. What am I missing. I only have these class. Rest I have one Controller

Edited I have made by code work by adding this class

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

1条回答
放荡不羁爱自由
2楼-- · 2019-06-01 01:36

I'm the writer of the link you refered.

Which data source do you use with Table1Repo?

You have to inject the specific bean "dataSource" to you JDBC call.

I guess @Primary "writeDataSource" is injected to your Repository.

Try to change @Primary to "dataSource" or find a way to inject "dataSource" to your repository.

查看更多
登录 后发表回答