从Spring Boot连接到Heroku Postgres

2022-09-02 08:52:17

我正在寻找使用JPA / Hibernate在Spring Boot应用程序中连接到Heroku Postgres的最简单,最干净的方式。

我在Heroku或Spring Boot文档中都没有看到这个组合的一个好的,完整的示例,所以我想在Stack Overflow上记录这一点。

我正在尝试使用这样的东西:

@Configuration   
public class DataSourceConfig {

    Logger log = LoggerFactory.getLogger(getClass());

    @Bean
    @Profile("postgres")
    public DataSource postgresDataSource() {        
        String databaseUrl = System.getenv("DATABASE_URL")
        log.info("Initializing PostgreSQL database: {}", databaseUrl);

        URI dbUri;
        try {
            dbUri = new URI(databaseUrl);
        }
        catch (URISyntaxException e) {
            log.error(String.format("Invalid DATABASE_URL: %s", databaseUrl), e);
            return null;
        }

        String username = dbUri.getUserInfo().split(":")[0];
        String password = dbUri.getUserInfo().split(":")[1];
        String dbUrl = "jdbc:postgresql://" + dbUri.getHost() + ':' 
            + dbUri.getPort() + dbUri.getPath();

        // fully-qualified class name to distuinguish from javax.sql.DataSource 
        org.apache.tomcat.jdbc.pool.DataSource dataSource 
            = new org.apache.tomcat.jdbc.pool.DataSource();
        dataSource.setUrl(dbUrl);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }

}

我正在使用Profiles,这似乎与我想要的很匹配:在Heroku上设置为,而在本地开发中则使用H2内存数据库(此处省略了其配置)。此方法似乎工作正常。SPRING_PROFILES_ACTIVEpostgresspring.profiles.activeh2

In(特定于配置文件的属性):application-postgres.properties

spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.datasource.driverClassName=org.postgresql.Driver

DataSource从Tomcat似乎是一个不错的选择,因为默认依赖项包含它,并且因为Spring Boot参考指南说

我们更喜欢Tomcat池化数据源的性能和并发性,因此如果可用,我们总是选择它。

(我也从Commons DBCP看到与Spring Boot一起使用。但对我来说,这似乎不是最干净的选择,因为默认的依赖项不包括Commons DBCP。总的来说,我想知道Apache Commons是否真的可以在2015年成为连接到Postgres的推荐方式......Heroku文档也为这种情况提供了“在春天”;我假设这是指Commons DBCP,因为我在Spring本身没有看到这样的类。BasicDataSourceBasicDataSource

依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>       
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
</dependency>
<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>9.4-1205-jdbc42</version>
</dependency>

当前状态:失败,并显示“未将 JDBC 驱动程序作为驱动程序类名属性加载为 null”:

eConfig$$EnhancerBySpringCGLIB$$463388c1 : Initializing PostgreSQL database: postgres:[...]
j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default'
org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found
[...]
o.a.tomcat.jdbc.pool.PooledConnection    : Not loading a JDBC driver as driverClassName property is null.    
o.a.tomcat.jdbc.pool.PooledConnection    : Not loading a JDBC driver as driverClassName property is null.
[...]
org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.PostgreSQLDialect

在日志中,我看到我的被调用得很好,并且PostgreSQLDialect正在使用中(如果没有这个,它就失败了,因为“当'hibernate.dialect'未设置时,对DialectResolutionInfo的访问不能为空”)。postgresDataSource

我的具体问题

  1. 那么,如何让它工作?我正在设置,那么为什么“不加载JDBC驱动程序作为驱动程序类名属性为空”?spring.datasource.driverClassName
  2. 是使用Tomcat的罚款还是你会推荐其他东西?DataSource
  3. 是否必须使用特定版本定义上述依赖项?(如果没有这个,我收到“找不到合适的驱动程序”错误。postgresql
  4. 有没有更简单的方法来完成所有这些(同时坚持Java代码和/或属性;请不要使用XML)?

答案 1

Spring Boot 2.x最簡單的清潔方式,搭配 Heroku & Postgres

我阅读了所有答案,但没有找到Jonik想要的东西:

我正在寻找使用JPA / Hibernate在Spring Boot应用程序中连接到Heroku Postgres的最简单,最干净的方式

大多数人希望与Spring Boot和Heroku一起使用的开发过程包括一个用于测试和快速开发周期的本地H2内存数据库 - 以及用于在Heroku上进行暂存和生产的Heroku Postgres数据库

  • 第一件事是 - 你不需要为此使用Spring配置文件!
  • 第二:你不需要编写/更改任何代码!

让我们一步一步来看看我们必须做些什么。我有一个示例项目,它为Postgres提供了一个完全工作的Heroku部署和配置 - 只是为了完整性,如果你想自己测试它:github.com/jonashackt/spring-boot-vuejs

啪啪啪.xml

我们需要以下方面:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <!-- In-Memory database used for local development & testing -->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
    </dependency>

    <!-- Switch back from Spring Boot 2.x standard HikariCP to Tomcat JDBC,
    configured later in Heroku (see https://stackoverflow.com/a/49970142/4964553) -->
    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-jdbc</artifactId>
    </dependency>

    <!-- PostgreSQL used in Staging and Production environment, e.g. on Heroku -->
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>42.2.2</version>
    </dependency>

这里有一个棘手的事情是 的用法,但我们稍后会介绍它。tomcat-jdbc

在 Heroku 上配置环境变量

在 Heroku 环境中,变量被命名为 。您没听错,我们所要做的就是配置环境变量!我们只需要正确的。因此,请转到 https://data.heroku.com/(我假设已经为您的Heroku应用程序配置了Postgres数据库,这是默认行为)。Config Vars

现在,单击应用程序的相应内容并切换到该选项卡。然后单击 ,其应类似于以下内容:DatastoreSettingsView Credentials...

heroku-datastore-credentials-postgres

现在打开一个新的浏览器选项卡,然后转到Heroku应用程序的选项卡。单击并创建以下环境变量:SettingsReveal Config Vars

  • SPRING_DATASOURCE_URL = jdbc:p ostgresql://YourPostgresHerokuHostNameHere:5432/YourPostgresHerokuDatabaseNameHere(注意前导和添加!)jdbc:qlpostgres
  • SPRING_DATASOURCE_USERNAME= YourPostgresHerokuUserNameHere
  • SPRING_DATASOURCE_PASSWORD= YourPostgresHerokuPasswordHere
  • SPRING_DATASOURCE_DRIVER-CLASS-NAME= org.postgresql.Driver(这并不总是必需的,因为Spring Boot可以从url推断出大多数数据库,只是为了这里的完整性)
  • SPRING_JPA_DATABASE-PLATFORM = org.hibernate.dialect.PostgreSQLDialect
  • SPRING_DATASOURCE_TYPE = org.apache.tomcat.jdbc.pool.DataSource
  • SPRING_JPA_HIBERNATE_DDL-AUTO = update(这将根据您的JPA实体自动创建您的表,这真的很棒-因为您不需要使用SQL语句或DDL文件来障碍)CREATE

在 Heroku 中,这应该如下所示:

heroku-spring-boot-app-postgres-config

现在,这就是您所要做的!每次更改配置变量时,您的 Heroku 应用程序都会重新启动 - 因此您的应用程序现在应该在本地运行 H2,并且在 Heroku 上部署时应准备好与 PostgreSQL 连接。

如果你问:为什么我们配置Tomcat JDBC而不是Hikari。

您可能已经注意到,我们将依赖项添加到 pom.xml并配置为环境变量。关于这句话,文档中只有一点点提示tomcat-jdbcSPRING_DATASOURCE_TYPE=org.apache.tomcat.jdbc.pool.DataSource

您可以完全绕过该算法,并通过设置 spring.datasource.type 属性来指定要使用的连接池。如果您在 Tomcat 容器中运行应用程序,这一点尤其重要,...

有几个原因我切换回Tomcat池数据源,而不是使用Spring Boot 2.x标准HikariCP。正如我在这里已经解释过的,如果你没有指定,Spring将尝试自动连接嵌入式im-memory H2数据库,而不是我们的PostgreSQL数据库。Hikari的问题在于,它只支持 。spring.datasource.urlspring.datasource.jdbc-url

其次,如果我尝试使用Hikari所示的Heroku配置(因此省略并更改为),我会遇到以下异常:SPRING_DATASOURCE_TYPESPRING_DATASOURCE_URLSPRING_DATASOURCE_JDBC-URL

Caused by: java.lang.RuntimeException: Driver org.postgresql.Driver claims to not accept jdbcUrl, jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE

因此,我没有让Spring Boot 2.x使用HikariCP在Heroku和Postgres上工作,而是使用Tomcat JDBC - 我也不想制动我的开发过程,其中包含预先描述的本地H2数据库。请记住:我们正在寻找使用JPA / Hibernate在Spring Boot应用程序中连接到Heroku Postgres的最简单,最干净的方式!


答案 2

最简单的弹簧靴/Heroku/休眠配置

除了 始终存在的 之外,Heroku 还在运行时创建了 3 个环境变量。它们是:DATABASE_URL

JDBC_DATABASE_URL
JDBC_DATABASE_USERNAME
JDBC_DATABASE_PASSWORD

如您所知,如果 Spring Boot 在文件中找到属性,它将自动配置您的数据库。下面是我的应用程序的一个示例。spring.datasource.*application.properties

spring.datasource.url=${JDBC_DATABASE_URL}
spring.datasource.username=${JDBC_DATABASE_USERNAME}
spring.datasource.password=${JDBC_DATABASE_PASSWORD}
spring.jpa.show-sql=false
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=update

休眠/后格雷斯依赖关系

在我的情况下,我使用的是Hibernate(与PostgreSQL捆绑在一起),所以我需要在我的:spring-boot-starter-jpabuild.gradle

dependencies {
    compile("org.springframework.boot:spring-boot-starter-data-jpa")
    compile('org.postgresql:postgresql:9.4.1212')
}

推荐