用例
我有一些客户,每个客户都运行自己的后端实例,该实例连接到自己的数据库,每个后端实例都有自己的数据库,但用于连接到这些数据库的凭据(主数据库)都是相同的,并且这些凭据是在另一个数据库中,无论后端实例如何,我的观点是在 Spring Data Jpa 上配置一个数据库连接,其凭据依赖于另一个数据库(它们存在于该数据库的映射实体上),然后我创建了一个包含数据库凭据的
Entity
(和其他信息):
@Data
public class Assinante {
@Id
@Column(name="cnpj_da_base")
private String cnpj;
@Column(name="db_jdbc_url")
private String databaseURL;
@Column(name="db_user")
private String databaseUser;
@Column(name="db_password")
private String databasePassword;
@Enumerated(EnumType.STRING)
private Categoria classificacao;
@Column(name="token_varejo")
private String tokenVarejo;
@Column(name="api_url")
private String apiUrl;
@Column(name="proxy_url")
private String proxyUrl;
@Column(name="proxy_https_port")
private Integer proxyHttpsPort;
@Column(name="proxy_login")
private String proxyLogin;
@Column(name="proxy_pass")
private String proxyPass;
@Column(name="valido_ate")
private LocalDate validoAte;
}
我需要一种方法来根据该实体中的凭据设置主数据库源,然后我这样做了:
对于主数据库:
@Configuration
@EnableJpaRepositories(
basePackages = "org.crm", // Adjusted package for primary repositories
entityManagerFactoryRef = "mainEntityManagerFactory",
transactionManagerRef = "mainTransactionManager",
excludeFilters = @ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE, classes = {
AssinanteRepository.class
}
)
)
public class DataSourceConfig {
@Value("{app.assinante-cnpj}")
private String cnpj;
@Autowired
private EntityManager entityManager;
private HikariConfig hikariConfig;
@PostConstruct
public void init() {
SimpleJpaRepository assinanteRepository = new SimpleJpaRepository<Assinante, String>(Assinante.class, entityManager);
Optional<Assinante> assinante = assinanteRepository.findById(cnpj);
if (assinante.isEmpty()) {
throw new RuntimeException("CNPJ NÃO ASSINADO");
}
// Configurações do Hikari baseadas no assinante
hikariConfig.setJdbcUrl(assinante.get().getDatabaseURL());
hikariConfig.setUsername(assinante.get().getDatabaseUser());
hikariConfig.setPassword(assinante.get().getDatabasePassword());
// Supondo que você tenha outras propriedades no objeto Assinante
hikariConfig.setConnectionTestQuery("SELECT 1");
hikariConfig.setValidationTimeout(3000);
hikariConfig.setIdleTimeout(60000);
hikariConfig.setMaxLifetime(1800000);
hikariConfig.setMinimumIdle(5);
hikariConfig.setMaximumPoolSize(20);
}
@Bean
@Primary
public DataSource dataSource() throws Exception {
return new HikariDataSource(hikariConfig);
}
@Bean
@Primary
public LocalContainerEntityManagerFactoryBean mainEntityManagerFactory() throws Exception {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setDataSource(dataSource());
factory.setPackagesToScan("org.crm"); // Main packages to scan
factory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
Properties properties = new Properties();
properties.put("hibernate.physical_naming_strategy", "org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy");
properties.put("hibernate.implicit_naming_strategy", "org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy");
factory.setJpaProperties(properties);
return factory;
}
@Bean
@Primary
public JpaTransactionManager mainTransactionManager(EntityManagerFactory mainEntityManagerFactory) {
return new JpaTransactionManager(mainEntityManagerFactory);
}
}
对于包含凭据的数据库:
@Configuration
@EnableJpaRepositories(
basePackages = "org.crm.domain.entidadesBusiness.assinantesSistema", // Pacote onde está o repositório do Assinante
entityManagerFactoryRef = "assinanteEntityManagerFactory",
transactionManagerRef = "assinanteTransactionManager"
)
public class AssinanteDataSourceConfig {
@Bean
public DataSource assinanteDataSource() {
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setJdbcUrl("secret");
hikariConfig.setUsername("secret");
hikariConfig.setPassword("secret");
// Configurações do HikariCP
hikariConfig.setConnectionTestQuery("SELECT 1");
hikariConfig.setValidationTimeout(3000);
hikariConfig.setIdleTimeout(60000);
hikariConfig.setMaxLifetime(1800000);
hikariConfig.setMinimumIdle(5);
hikariConfig.setMaximumPoolSize(20);
return new HikariDataSource(hikariConfig);
}
@Bean
public LocalContainerEntityManagerFactoryBean assinanteEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setDataSource(assinanteDataSource());
factory.setPackagesToScan(Assinante.class.getPackageName());
factory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
Properties properties = new Properties();
properties.put("hibernate.physical_naming_strategy", "org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy");
properties.put("hibernate.implicit_naming_strategy", "org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy");
factory.setJpaProperties(properties);
return factory;
}
@Bean
public JpaTransactionManager assinanteTransactionManager(EntityManagerFactory assinanteEntityManagerFactory) {
return new JpaTransactionManager(assinanteEntityManagerFactory);
}
}
问题是当我运行应用程序时,我在
EntityManager
和 DataSource
之间出现了循环依赖
我通过将注释
@Primary
移动到包含凭据的数据库并使用 解决了这个问题
@Autowired
private EntityManagerFactory entityManagerFactory;
与
EntityManager entityManager = entityManagerFactory.createEntityManager();
相反
@Autowired
private EntityManager entityManager;