通过TNS与Oracle的连接不工作

通过TNS与Oracle的连接不工作,oracle,spring-boot,tnsnames,tns,Oracle,Spring Boot,Tnsnames,Tns,我有一个Spring Boot应用程序,当它以经典的方式连接到Oracle实例时,它可以顺利工作: jdbc:oracle:thin:@<server name>:<port num>/<service name> 以下是我的application.properties+application-oracleprod.properties文件。请记住,如前所述,当我使用SID连接时,这种方法是有效的 application.properties: spring

我有一个Spring Boot应用程序,当它以经典的方式连接到Oracle实例时,它可以顺利工作:

jdbc:oracle:thin:@<server name>:<port num>/<service name>
以下是我的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(此处的神奇之处在于该属性“oracle.net.tns_admin”设置了“tnsnames.ora”文件夹和链接“@MY_SERVICE”,该链接显然存在于“tnsnames.ora”文件中,但我真的看不到oracle在幕后做什么):

配置类简洁明了:

@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引导配置文件/类,但运气不佳

我还尝试了不同的路径格式:

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> )
      )
    )
  )
再一次,我有点困惑如何告诉Spring如何阅读这个TNS配置


有什么想法吗?

在您的类中,您基本上禁用了自动配置,从而使大部分
应用程序的属性变得无用

您的
OracleConfiguration
中没有任何内容不是(或可以)为您自动配置的

注意:我假设有两件事,第一件是用作连接池,第二件是使用Spring Boot 1.4.x

因此,对于初学者来说,删除
OracleConfiguration
类并相应地修复
应用程序.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类名,因为它将从URL派生

在您的
应用程序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.datasourceproperty
来设置
OracleDataSource
中的附加属性

这应该允许Spring Boot自动创建
数据源
和相应的
EntityManager工厂
,而无需创建自定义配置类

更新(配置不带Hikari和普通的
OracleDataSource
) 如果要使用普通的
OracleDataSource
而不是连接池,可以从默认的
应用程序.properties
中删除
spring.datasource.type
,并将以下内容添加到
应用程序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
其结果或多或少与您手动配置的结果相同

更新#2 要使用TNS,还需要设置名为
oracle.net.TNS\u admin的系统属性。(见附件)

因此,在应用程序初始值设定项中(如果未在应用程序服务器上设置),您需要手动设置它

private static void 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
onstart
configure
方法调用此方法。这假设您的环境中设置了
ORACLE\u HOME
TNS\u ADMIN
变量。

出于某种原因,仅对我有效:

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:@myu服务。

另外,我正在调用用户m.Deinum在接受的答案中建议的determineAndSettnHome()方法:

public static void main(String[] args) {
        SpringApplication.run(EvaApplication.class, args);
        determineAndSetTnsHome();
    }
实际上是跛脚的方法,, 但它工作得很好

把这个放在你的主课上

    System.setProperty("oracle.net.tns_admin",
            "<Path of tnsnames.ora>");
System.setProperty(“oracle.net.tns_admin”,
"");
在属性文件中使用此选项

spring.datasource.url=jdbc:oracle:thin:@ORCLPDB


我还在挖。将在此处更新

您在此处输入了大量代码,任何人都很难先理解您的问题,然后再回答。提问时请具体、准确。在发布问题之前,请先看一看。您正在将spring.jpa.database-platform设置为Oracle方言,是否也尝试过设置hibernate属性?(按照异常中的要求)因此,您正在应用程序中设置属性。属性用于自动配置。接下来创建您自己的配置,禁用自动配置,并发现没有应用这些属性很奇怪。简而言之,
应用程序中没有属性。将使用/应用属性。问题出现了,为什么你有这个配置类?您并不真正需要它,因为Spring Boot可以为您即时配置所有这些。@GeekyNinja省略这些代码不会显示完整且可验证的代码example@Turo我不明白你指的是哪一处房产。你能解释清楚吗?谢谢。它实际上与SID连接一起工作。但是,我仍然面临TNS连接的问题。此时,我想知道配置类的用途。是否需要在不依赖.properties文件的情况下手动配置数据源(在代码中指定连接条件)?您不需要配置类。(你在评论中提出的问题是另一个问题)。我非常怀疑,对于这个配置文件,您是否会得到相同的异常(如果您删除了配置类)。我已经更新了主要问题。TNS连接的问题仍然存在,但我当然误解了数据源配置。你救了我一天。我想知道为什么在.properties文件中添加属性“oracle.net.tns_admin”不会起作用。这肯定会更干净、更高效。我将进一步研究一种不在spring引导“Application.java”中添加额外代码的方法。原因是我会离开李
spring.datasource.url=jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)(HOST=TODO)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=TODO)))
public static void main(String[] args) {
        SpringApplication.run(EvaApplication.class, args);
        determineAndSetTnsHome();
    }
    System.setProperty("oracle.net.tns_admin",
            "<Path of tnsnames.ora>");