Тест Sharding с Springboot и mysql - PullRequest
0 голосов
/ 17 марта 2020

Я пытаюсь протестировать простой пример шардинга. У меня есть таблица User с несколькими полями. Значения firstName между a и m должны храниться в shard1, а между n и z должны храниться в shard2. Есть 2 схемы shard1 и shard2. Оба настроены, но данные всегда хранятся в shard2. spring.main.allow-bean-definition-overriding=true запускает приложение, но это shard2 менеджер транзакций ovveride shard1. Если не задано это значение, генерируется исключение о том, что userrepository уже существует для shard1. Как я могу заставить это работать. Ниже мой код.

Shard1Config

@Configuration
@EnableJpaRepositories(basePackages = "com.sharding.shardexample.model", entityManagerFactoryRef = "shard1EntityManagerFactory",
        transactionManagerRef = "shard1TransactionManager" )
@EntityScan(basePackages = "com.sharding.shardexample.model")
public class Shard1Configuration {
    @Autowired
    private Environment env;

    @Bean
    @ConfigurationProperties(prefix="datasource.shard1")
    public DataSourceProperties shard1DataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean
    public DataSource shard1DataSource() {
        DataSourceProperties shard1DataSourceProperties = shard1DataSourceProperties();
        return DataSourceBuilder.create()
                .driverClassName(shard1DataSourceProperties.getDriverClassName())
                .url(shard1DataSourceProperties.getUrl())
                .username(shard1DataSourceProperties.getUsername())
                .password(shard1DataSourceProperties.getPassword())
                .build();
    }

    @Bean
    public PlatformTransactionManager shard1TransactionManager()
    {
        EntityManagerFactory factory = shard1EntityManagerFactory().getObject();
        return new JpaTransactionManager(factory);
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean shard1EntityManagerFactory()
    {
        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setDataSource(shard1DataSource());
        factory.setPackagesToScan(new String[]{"com.sharding.shardexample.model"});
        factory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());

        Properties jpaProperties = new Properties();
        jpaProperties.put("hibernate.hbm2ddl.auto", env.getProperty("spring.jpa.hibernate.ddl-auto"));
        jpaProperties.put("hibernate.show-sql", env.getProperty("spring.jpa.show-sql"));
        factory.setJpaProperties(jpaProperties);

        return factory;
    }

    @Bean
    public DataSourceInitializer shard1DataSourceInitializer()
    {
        DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();
        dataSourceInitializer.setDataSource(shard1DataSource());
        //esourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
        //databasePopulator.addScript(new ClassPathResource("shard1-data.sql"));
        //dataSourceInitializer.setDatabasePopulator(databasePopulator);
        dataSourceInitializer.setEnabled(env.getProperty("datasource.shard1.initialize", Boolean.class, true));
        return dataSourceInitializer;
    }
}


Shard2Config

@Configuration
@EnableJpaRepositories(basePackages = "com.sharding.shardexample.model", entityManagerFactoryRef = "shard2EntityManagerFactory",
        transactionManagerRef = "shard2TransactionManager" )
@EntityScan(basePackages = "com.sharding.shardexample.model")
public class Shard2Configuration {
    @Autowired
    private Environment env;

    @Bean
    @ConfigurationProperties(prefix="datasource.shard2")
    public DataSourceProperties shard2DataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean
    public DataSource shard2DataSource() {
        DataSourceProperties shard2DataSourceProperties = shard2DataSourceProperties();
        return DataSourceBuilder.create()
                .driverClassName(shard2DataSourceProperties.getDriverClassName())
                .url(shard2DataSourceProperties.getUrl())
                .username(shard2DataSourceProperties.getUsername())
                .password(shard2DataSourceProperties.getPassword())
                .build();
    }

    @Bean
    public PlatformTransactionManager shard2TransactionManager()
    {
        EntityManagerFactory factory = shard2EntityManagerFactory().getObject();
        return new JpaTransactionManager(factory);
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean shard2EntityManagerFactory()
    {
        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setDataSource(shard2DataSource());
        factory.setPackagesToScan(new String[]{"com.sharding.shardexample.model"});
        factory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());

        Properties jpaProperties = new Properties();
        jpaProperties.put("hibernate.hbm2ddl.auto", env.getProperty("spring.jpa.hibernate.ddl-auto"));
        jpaProperties.put("hibernate.show-sql", env.getProperty("spring.jpa.show-sql"));
        factory.setJpaProperties(jpaProperties);

        return factory;
    }

    @Bean
    public DataSourceInitializer shard2DataSourceInitializer()
    {
        DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();
        dataSourceInitializer.setDataSource(shard2DataSource());
        //esourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
        //databasePopulator.addScript(new ClassPathResource("shard2-data.sql"));
        //dataSourceInitializer.setDatabasePopulator(databasePopulator);
        dataSourceInitializer.setEnabled(env.getProperty("datasource.shard2.initialize", Boolean.class, true));
        return dataSourceInitializer;
    }
}


User
@Entity(name = "USER")
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User {


    @Id
    @GeneratedValue(generator = "UUID")
    @GenericGenerator(name = "UUID", strategy ="org.hibernate.id.UUIDGenerator")
    @Column(name="ID",unique = false,nullable = false)
    private String id;

    @Column(name = "FIRST_NAME")
    private String firstName;

    @Column(name = "LAST_NAME")
    private String lastName;

    @Column(name = "AGE")
    private String age;
}



UserService
@Component
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public List<User> getUser(String name) {
        return (List<User>) userRepository.findByFirstName(name);
    }

    public List<User> getAllUsers() {
        return (List<User>) userRepository.findAll();
    }

    public void addUser(UserRequest request) {
        User user = User.builder()
                .firstName(request.getFirstName())
                .lastName(request.getLastName())
                .age(request.getAge())
                .build();
        char firstChar = request.getFirstName().charAt(0);
        if((firstChar >= 'A' || firstChar >='a') && (firstChar <= 'M' || firstChar <= 'm')) {
            saveInShard1(user);
        } else {
            saveInShard2(user);
        }

    }

    @Transactional(transactionManager = "shard1TransactionManager")
    private void saveInShard1(User user) {
        userRepository.save(user);
    }

    @Transactional(transactionManager = "shard2TransactionManager")
    private void saveInShard2(User user) {
        userRepository.save(user);
    }

}


application.properties
datasource.shard1.driver-class-name=com.mysql.jdbc.Driver
datasource.shard1.url=jdbc:mysql://localhost:3306/shard1
datasource.shard1.username=root
datasource.shard1.password=

datasource.shard1.initialize=true

datasource.shard2.driver-class-name=com.mysql.jdbc.Driver
datasource.shard2.url=jdbc:mysql://localhost:3306/shard2
datasource.shard2.username=root
datasource.shard2.password=

datasource.shard2.initialize=true


spring.main.allow-bean-definition-overriding=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

1 Ответ

0 голосов
/ 17 марта 2020

Оказывается, я слишком усложнял вещи. Мне нужно было использовать пользовательскую версию AbstractRoutingDataSource, чтобы решить эту проблему. Все решение можно увидеть здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...