首页 > 解决方案 > postgres 的 Springboot application.properties 不起作用 - 致命:数据库“null”不存在

问题描述

我遇到的问题是Springboot版本的自动配置:1.5.9.RELEASE似乎没有效果。

请注意,如果我定义一个返回 DataSource bean 的 bean,我可能能够克服我当前的问题。

可能 DataSource bean 可能看起来非常类似于: 以下代码段中的示例: https ://www.atomikos.com/Documentation/ConfiguringPostgreSQL

我正在切换我的 application.properties 配置以停止使用 spring boot 使用的默认 H2 数据库并将其切换到 postgres。

以下页面中说明的配置片段: https ://dzone.com/articles/configuring-spring-boot-for-postgresql

肯定是不行的。这是我的配置的样子:

spring.datasource.url=jdbc:postgresql://localhost:5432/dummydb
spring.datasource.username=DUMMYDB
spring.datasource.password=DUMMYDB
spring.jpa.hibernate.ddl-auto=create-drop

这不起作用,为什么?显然出于一个非常简单的原因。虽然用户名和密码肯定是有用的,并且在连接工厂尝试为数据库建立连接时被转移。在配置数据源时,URL 属性是没有用的。

让我首先给你最后的堆栈跟踪:

Caused by: org.postgresql.util.PSQLException: FATAL: database "null" does not exist
    at org.postgresql.core.v3.ConnectionFactoryImpl.readStartupMessages(ConnectionFactoryImpl.java:469) ~[postgresql-9.1-901.jdbc4.jar:na]
    at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:112) ~[postgresql-9.1-901.jdbc4.jar:na]
    at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:66) ~[postgresql-9.1-901.jdbc4.jar:na]
    at org.postgresql.jdbc2.AbstractJdbc2Connection.<init>(AbstractJdbc2Connection.java:125) ~[postgresql-9.1-901.jdbc4.jar:na]
    at org.postgresql.jdbc3.AbstractJdbc3Connection.<init>(AbstractJdbc3Connection.java:30) ~[postgresql-9.1-901.jdbc4.jar:na]
    at org.postgresql.jdbc3g.AbstractJdbc3gConnection.<init>(AbstractJdbc3gConnection.java:22) ~[postgresql-9.1-901.jdbc4.jar:na]
    at org.postgresql.jdbc4.AbstractJdbc4Connection.<init>(AbstractJdbc4Connection.java:30) ~[postgresql-9.1-901.jdbc4.jar:na]
    at org.postgresql.jdbc4.Jdbc4Connection.<init>(Jdbc4Connection.java:24) ~[postgresql-9.1-901.jdbc4.jar:na]
    at org.postgresql.Driver.makeConnection(Driver.java:393) ~[postgresql-9.1-901.jdbc4.jar:na]
    at org.postgresql.Driver.connect(Driver.java:267) ~[postgresql-9.1-901.jdbc4.jar:na]
    at java.sql.DriverManager.getConnection(DriverManager.java:664) ~[na:1.8.0_112]
    at java.sql.DriverManager.getConnection(DriverManager.java:247) ~[na:1.8.0_112]
    at org.postgresql.ds.common.BaseDataSource.getConnection(BaseDataSource.java:91) ~[postgresql-9.1-901.jdbc4.jar:na]
    at org.postgresql.xa.PGXADataSource.getXAConnection(PGXADataSource.java:47) ~[postgresql-9.1-901.jdbc4.jar:na]
    at org.postgresql.xa.PGXADataSource.getXAConnection(PGXADataSource.java:32) ~[postgresql-9.1-901.jdbc4.jar:na]
    at com.atomikos.jdbc.AtomikosXAConnectionFactory.createPooledConnection(AtomikosXAConnectionFactory.java:60) ~[transactions-jdbc-3.9.3.jar:na]
    ... 44 common frames omitted

为什么这不起作用是因为 postgres 基础数据源根本不关心通过 URL 配置。相反,它希望通过传递的 setter 进行配置:databaseName、port 等...请查看以下类:

org.postgresql.ds.common.BaseDataSource

这个类提供了多个setter。对于用户名、密码等。但是没有设置 URL 的方法。构成 URL 的各个元素(例如数据库名称)需要进入专用字段。

因此,该类提供的是这个 getURL() 方法,它正在重新调整数据库为空的奇怪 URL。这是该方法的代码片段。

/**
     * Generates a DriverManager URL from the other properties supplied.
     */
    private String getUrl()
    {
        StringBuffer sb = new StringBuffer(100);
        sb.append("jdbc:postgresql://");
        sb.append(serverName);
        if (portNumber != 0) {
            sb.append(":").append(portNumber);
        }
        sb.append("/").append(databaseName);
        sb.append("?loginTimeout=").append(loginTimeout);
        sb.append("&socketTimeout=").append(socketTimeout);
        sb.append("&prepareThreshold=").append(prepareThreshold);
        sb.append("&unknownLength=").append(unknownLength);
        sb.append("&loglevel=").append(logLevel);
        if (protocolVersion != 0) {
            sb.append("&protocolVersion=").append(protocolVersion);
        }
        if (ssl) {
            sb.append("&ssl=true");
            if (sslfactory != null) {
                sb.append("&sslfactory=").append(sslfactory);
            }
        }
        sb.append("&tcpkeepalive=").append(tcpKeepAlive);
        if (compatible != null) {
            sb.append("&compatible="+compatible);
        }
        if (applicationName != null) {
            sb.append("&ApplicationName=");
            sb.append(applicationName);
        }

        return sb.toString();
    }

所以我的问题是。好的......如果不希望通过 url 而是通过各种不同的设置器配置 postgres 数据源,也许我可以通过添加到 application.properties 文件字段来摆脱,例如:

#spring.datasource.databaseName=dummydb

不,事实证明这似乎根本没有用。

经过一番调试,我设法找出了这个spring boot自动配置类:

org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration

上面的类非常有趣,因为它位于原子 JTA 事务子系统的配置路径上。IT 将设置数据源:

org.postgresql.xa.PGXADataSource

但唯一的问题是这个自动配置器只关心我们的 application.properties 文件中的三个属性。请参阅下面的代码片段:

private void bindXaProperties(XADataSource target, DataSourceProperties properties) {
        MutablePropertyValues values = new MutablePropertyValues();
        values.add("user", this.properties.determineUsername());
        values.add("password", this.properties.determinePassword());
        values.add("url", this.properties.determineUrl());
        values.addPropertyValues(properties.getXa().getProperties());
        new RelaxedDataBinder(target).withAlias("user", "username").bind(values);
    }

如您所见,我似乎被“烤了”。自动配置器没有任何其他可能相关的数据源属性的概念。至少可以说,这让我感到惊讶。我期待某种类没有任何东西,例如用户名和密码等属性的硬编码子集。我期待某种代码可以轻松地循环所有 applicaton.properties 并寻找其键开头的任何属性:

spring.datasource.whatever

并在数据源类上调用 datasource.setWhatever。

似乎并非如此。

所以我确定我一定是搞砸了。我不敢相信如果不强制开发人员创建自己的数据源 bean,springboot 将无法配置 postgres 数据库。Postgress 简直太主流了...

所以我想知道是否有人可以帮助我弄清楚如何正确配置 application.properties 文件以确保我确实可以使用 springboot 连接到 postgres。

同时,我将看看我是否可以通过以编程方式创建一个类来解决这个问题:

@AutoConfigureBefore(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties(DataSourceProperties.class)
@ConditionalOnClass({ DataSource.class, TransactionManager.class,
        EmbeddedDatabaseType.class })
@ConditionalOnBean(XADataSourceWrapper.class)
@ConditionalOnMissingBean(DataSource.class)
public class XADataSourceAutoConfiguration implements BeanClassLoaderAware {

但在我的情况下,该类将知道如何以编程方式构建具有所有必要属性的 postgres 数据源以进行连接。

非常感谢您的帮助。

标签: postgresqlspring-bootconfiguration

解决方案


推荐阅读