我有以下问题。我必须使用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)是在项目中作为依赖项包含的外部jar中定义的。
当我尝试使用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]
如果我在Web应用程序内部移动实体(例如第一个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");
,但我又有第二个例外。确实,我需要使用外部实体并映射一个双数据源。
谁能帮我?感谢您的支持。