我有一个Spring Boot应用程序,它以经典的方式连接到Oracle实例时运行顺畅:
jdbc:oracle:thin:@<server name>:<port num>/<service name>
然而,当我通过tns通过存储在我的本地驱动器中的tnsnames.ora转向连接时,&#34; C:\ ORACLE \ Client11g \ network \ admin&#34;有些东西不起作用,我得到了这个例外:
Caused by: org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:267)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:231)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:210)
at org.hibernate.engine.jdbc.internal.JdbcServicesImpl.configure(JdbcServicesImpl.java:51)
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:94)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:240)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:210)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.handleTypes(MetadataBuildingProcess.java:352)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:111)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:858)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:885)
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:60)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:353)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:373)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:362)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1642)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1579)
... 36 more
Caused by: org.hibernate.HibernateException: Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set
at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.determineDialect(DialectFactoryImpl.java:100)
at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.buildDialect(DialectFactoryImpl.java:54)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:137)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:35)
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:88)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:257)
... 52 more
10:37:32,201 ERROR [org.jboss.msc.service.fail] (ServerService Thread Pool -- 381) MSC000001: Failed to start service jboss.undertow.deployment.default-server.default-host./my_service: org.jboss.msc.service.StartException in service jboss.undertow.deployment.default-server.default-host./my_service: java.lang.RuntimeException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [app/persistence/OracleConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
at org.wildfly.extension.undertow.deployment.UndertowDeploymentService$1.run(UndertowDeploymentService.java:85)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
at org.jboss.threads.JBossThread.run(JBossThread.java:320)
Caused by: java.lang.RuntimeException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [app/persistence/OracleConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:236)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentService.startContext(UndertowDeploymentService.java:100)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentService$1.run(UndertowDeploymentService.java:82)
... 6 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [app/persistence/OracleConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1583)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1081)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:856)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:761)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:371)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
at org.springframework.boot.web.support.SpringBootServletInitializer.run(SpringBootServletInitializer.java:151)
at org.springframework.boot.web.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:131)
at org.springframework.boot.web.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:86)
at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:169)
at io.undertow.servlet.core.DeploymentManagerImpl$1.call(DeploymentManagerImpl.java:186)
at io.undertow.servlet.core.DeploymentManagerImpl$1.call(DeploymentManagerImpl.java:171)
at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:42)
at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44)
at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44)
at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44)
at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44)
at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44)
at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44)
at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:234)
... 8 more
以下是我的application.properties + application-oracleprod.properties文件。请记住,当我使用SID连接时,此方法可以正常工作。
application.properties:
spring.profiles.active=oracleprod
spring.jpa.database-platform=org.hibernate.dialect.Oracle10gDialect
spring.jpa.hibernate.ddl-auto=validate
hibernate.show_sql=true
hibernate.hbm2ddl.auto=update
hibernate.generate_statistics=true
application-oracleprod.properties(这里应该发生魔法,因为这个属性&#34; oracle.net.tns_admin&#34;它设置&#34; tnsnames.ora&#34;文件夹加上链接&#34 ; @ MY_SERVICE&#34;显然存在于&#34; tnsnames.ora&#34;文件中,但我真的不知道Oracle在幕后做了什么):
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
#/tnsnames.ora
oracle.net.tns_admin=C:/ORACLE/Client11g/network/admin
oracle.username=my_user
oracle.password=xyz
oracle.url=jdbc:oracle:thin:@MY_SERVICE
Configuration类干净简洁:
@Configuration
@ConfigurationProperties(prefix="oracle" )
public class OracleConfiguration {
@NotNull
private String username;
@NotNull
private String password;
@NotNull
private String url;
/*@Value("${oracle.net.tns_admin}")
private String tns;*/
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public void setUrl(String url) {
this.url = url;
}
/*public void setTns(String tns) {
this.tns = tns;
}*/
@Bean
DataSource dataSource() throws SQLException {
OracleDataSource dataSource = new OracleDataSource(); // we use oracle data source API but it could be mysql
dataSource.setURL(this.url);
dataSource.setUser(this.username);
dataSource.setPassword(this.password);
dataSource.setImplicitCachingEnabled(true);
dataSource.setFastConnectionFailoverEnabled(true);
return dataSource;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
try {
em.setDataSource(dataSource());
} catch (SQLException e) {
e.printStackTrace();
}
em.setPackagesToScan(new String[] { "app.persistence.entity" }); // put the name of entity classes package
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
//em.setJpaProperties(additionalProperties()); // this properties are set by "application-oracle.properties" file
return em;
}
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
总而言之,我已经遵循Oracle文档中建议的方法结合Spring Boot配置文件/类而没有运气。
我也尝试过不同的路径格式:
C:/ORACLE/Client11g/network/admin/tnsnames.ora
C:\ORACLE\Client11g\network\admin
C:\\ORACLE\\Client11g\\network\\admin
我认为我做得很好,因为通过SID连接,一切都很完美,但可能隐藏的内容很少。
更新
事实证明,db url不正确,至少对于TNS连接是这样。问题是我们有多个主机,而不仅仅是一个主机:
MY_SERVICE =
(DESCRIPTION_LIST =
(LOAD_BALANCE = off)
(FAILOVER = on)
(DESCRIPTION =
(CONNECT_TIMEOUT = 5)
(TRANSPORT_CONNECT_TIMEOUT = 3)
(RETRY_COUNT = 3)
(ADDRESS_LIST =
(LOAD_BALANCE = on)
(ADDRESS = (PROTOCOL = TCP)(HOST = <ip_1> )(PORT = 1621))
(ADDRESS = (PROTOCOL = TCP)(HOST = <ip_2> )(PORT = 1621))
)
(CONNECT_DATA =
(SERVICE_NAME = <my_service_name>)
)
)
(DESCRIPTION =
(CONNECT_TIMEOUT = 5)
(TRANSPORT_CONNECT_TIMEOUT = 3)
(RETRY_COUNT = 3)
(ADDRESS_LIST =
(LOAD_BALANCE = on)
(ADDRESS = (PROTOCOL = TCP)(HOST = <ip_3> )(PORT = 1621))
(ADDRESS = (PROTOCOL = TCP)(HOST = <ip_4> )(PORT = 1621))
)
(CONNECT_DATA =
(SERVICE_NAME = <my_service_name> )
)
)
)
我得到了:
javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory
Caused by: java.lang.RuntimeException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory
Caused by: org.hibernate.exception.JDBCConnectionException: Unable to open JDBC Connection for DDL execution
Caused by: java.sql.SQLRecoverableException: Errore di I/O: Unknown host specified
Caused by: oracle.net.ns.NetException: Unknown host specified "
同样,我对如何告诉Spring如何阅读此TNS配置感到有点困惑。
有什么想法吗?
答案 0 :(得分:1)
使用您的课程,您基本上禁用自动配置,因此很大一部分application.properties
无法使用。
OracleConfiguration
中没有任何内容(或可以)自动为您配置。
注意:我假设有两件事,首先您使用HikariCP作为连接池,然后使用Spring Boot 1.4.x.
首先,对于初学者,请删除OracleConfiguration
类并相应地修复application.properties
。
# DataSource
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
#JPA
spring.jpa.hibernate.ddl-auto=validate
#Hibernate
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.generate_statistics=true
您不需要spring.datasource.driver-class-name
,因为它将来自网址。
在application-oracle.properties
(或您使用的任何个人资料名称)中,设置以下内容
# DataSource
spring.datasource.username=my_user
spring.datasource.password=xyz
spring.datasource.url=jdbc:oracle:thin:@MY_SERVICE
spring.datasource.hikari.dataSourceClassName=oracle.jdbc.pool.OracleDataSource
spring.datasource.hikari.dataSourceProperties.implicitCachingEnabled=true
spring.datasource.hikari.dataSourceProperties.fastConnectionFailoverEnabled=true
#JPA
spring.jpa.database-platform=org.hibernate.dialect.Oracle10gDialect
这将配置oracle特定的JDBC属性。
在spring.datasource.hikari.dataSourceProperties
中设置其他属性需要OracleDataSource
。
这应该允许Spring Boot自动创建DataSource
和适当的EntityManagerFactory
,而无需根据需要创建自定义配置类。
OracleDataSource
的配置)如果您想使用普通OracleDataSource
而不是连接池,则可以从默认spring.datasource.type
中删除application.properties
,并将以下内容添加到application-oracle.properties
。
# DataSource
spring.datasource.type=oracle.jdbc.pool.OracleDataSource
spring.datasource.username=my_user
spring.datasource.password=xyz
spring.datasource.url=jdbc:oracle:thin:@MY_SERVICE
这与您手动配置的结果大致相同。
如果您想使用TNS,还需要设置名为oracle.net.tns_admin
的系统属性。 (见this question)。
因此,在您的应用程序初始化程序中(如果未在您的应用程序服务器上设置),您需要手动设置它。
private static determineAndSetTnsHome() {
String tnsAdmin = System.getenv("TNS_ADMIN");
if (tnsAdmin == null) {
String oracleHome = System.getenv("ORACLE_HOME");
if (oracleHome == null) {
return; //failed to find any useful env variables
}
tnsAdmin = oracleHome + File.separatorChar + "network" + File.separatorChar + "admin";
}
System.setProperty("oracle.net.tns_admin", tnsAdmin);
}
使用main
和onStartup
或configure
方法调用此方法。这假设您在环境中设置了ORACLE_HOME
或TNS_ADMIN
变量。
答案 1 :(得分:1)
出于某种原因,对我来说只有工作:
spring.datasource.url=jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)(HOST=TODO)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=TODO)))
而不是spring.datasource.url=jdbc:oracle:thin:@MY_SERVICE.
此外,我正在调用用户M. Deinum在接受的答案中建议的方法determineAndSetTnsHome():
public static void main(String[] args) {
SpringApplication.run(EvaApplication.class, args);
determineAndSetTnsHome();
}
答案 2 :(得分:0)
实际上是方法 但效果很好
将其放入您的主班。
System.setProperty("oracle.net.tns_admin",
"<Path of tnsnames.ora>");
在属性文件中使用它
spring.datasource.url = jdbc:oracle:thin:@ORCLPDB
我还在挖掘更多。将在此处提供更新