У меня следующая проблема.Мне нужно разработать приложение, используя springboot, hibernate и gradle.Мое приложение должно связываться с двумя разными базами данных, поэтому у меня есть: application.properties:
spring.db1.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.db1.datasource.url=jdbc:mysql://192.168.1.189:3306/db1?useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8&useSSL=false&serverTimezone=UTC
spring.db1.datasource.jdbcUrl=${spring.db1.datasource.url}
spring.db1.datasource.username=test
spring.db1.datasource.password=test
spring.db2.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.second.datasource.url=jdbc:mysql://192.168.1.189:3306/test_db?useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8&serverTimezone=UTC
spring.db2.datasource.jdbcUrl=${spring.db2.datasource.url}
spring.db2.datasource.username=test
spring.db2.datasource.password=test
Затем я написал два класса конфигурации для определения соединения с базами данных:
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "testDbEntityManager",
transactionManagerRef = "testDbTransactionManager")
public class TestdbDbConfig {
@Bean
@ConfigurationProperties(prefix = "spring.db1.datasource")
public DataSource testDbDataSource() {
return DataSourceBuilder
.create()
.build();
}
@Bean(name = "testDbEntityManager")
public LocalContainerEntityManagerFactoryBean testDbEntityManagerFactory(EntityManagerFactoryBuilder builder) {
Map<String, Object> properties = hibernateProperties();
return builder
.dataSource(testDbDataSource())
.properties(properties)
.packages(CustomObject.class)
.persistenceUnit("testDb1PU")
.build();
}
@Bean(name = "testDbTransactionManager")
public PlatformTransactionManager testDbTransactionManager(@Qualifier("testDbEntityManager") EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
private Map<String, Object> hibernateProperties() {
Resource resource = new ClassPathResource("hibernate.properties");
try {
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
return properties.entrySet().stream()
.collect(Collectors.toMap(
e -> e.getKey().toString(),
e -> e.getValue())
);
} catch (IOException e) {
return new HashMap<String, Object>();
}
}
}
и
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "testDb2EntityManager",
transactionManagerRef = "testDb2TransactionManager")
public class TestdbDbConfig {
@Bean
@ConfigurationProperties(prefix = "spring.db2.datasource")
public DataSource testDbDataSource() {
return DataSourceBuilder
.create()
.build();
}
@Bean(name = "testDb2EntityManager")
public LocalContainerEntityManagerFactoryBean testDbEntityManagerFactory(EntityManagerFactoryBuilder builder) {
Map<String, Object> properties = hibernateProperties();
return builder
.dataSource(testDbDataSource())
.properties(properties)
.packages(AgentCustomGui.class,
Area.class,
Company.class)
.persistenceUnit("testDb2PU")
.build();
}
@Bean(name = "testDb2TransactionManager")
public PlatformTransactionManager testDbTransactionManager(@Qualifier("testDb2EntityManager") EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
private Map<String, Object> hibernateProperties() {
Resource resource = new ClassPathResource("hibernate.properties");
try {
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
return properties.entrySet().stream()
.collect(Collectors.toMap(
e -> e.getKey().toString(),
e -> e.getValue())
);
} catch (IOException e) {
return new HashMap<String, Object>();
}
}
}
Проблема заключается в том, что для второй базы данных сущности (AgentCustomGui, Area, Company) определены во внешнем банке, включенном как зависимость в проект.Когда я пытаюсь запустить приложение с gradle (gradle bootRun
), у меня возникает следующее исключение:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testDb2EntityManager' defined in class path resource [it/testwebapp/config/TestdbDb2Config.class]: Invocation of init method failed; nested exception is java.lang.NullPointerException
...
Caused by: java.lang.NullPointerException: null
at org.hibernate.mapping.PersistentClass.createPrimaryKey(PersistentClass.java:363) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
at org.hibernate.cfg.CreateKeySecondPass.doSecondPass(CreateKeySecondPass.java:31) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1640) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1604) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:278) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:861) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:888) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:57) ~[spring-orm-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365) ~[spring-orm-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:390) ~[spring-orm-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:377) ~[spring-orm-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341) ~[spring-orm-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1758) ~[spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1695) ~[spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
Если я перемещаю сущности внутри моего веб-приложения (как первый CustomObject), все отлично работает сследующие свойства гибернации:
hibernate.id.new_generator_mappings=false
hibernate.format_sql=true
hibernate.temp.use_jdbc_metadata_defaults=false
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.current_session_context_class=org.hibernate.context.internal.ThreadLocalSessionContext
Я пытался нам hibernate.hbm2ddl.auto=validate
, но в этом случае у меня есть другое исключение: Невозможно построить Hibernate SessionFactory;вложенное исключение - org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: missing table [custom_object]
Я также попытался указать default_schema для обеих конфигураций: properties.put("hibernate.default_schema", "db1");
и properties.put("hibernate.default_schema", "test_db");
, но у меня снова второе исключение.На самом деле мне нужно использовать внешние объекты и сопоставить двойные источники данных.Может кто-нибудь мне помочь?Спасибо за поддержку.