Я пытаюсь протестировать простой пример шардинга. У меня есть таблица 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