【发布时间】:2015-09-18 10:08:01
【问题描述】:
我正在尝试将 Play Framework (2.4.2) 应用程序部署到 Heroku。我正在使用 JPA(带有 Hibernate 4.3.10 和 Postgres)。我也在运行JDK8。
抱歉,帖子太长了,但我想提供尽可能多的信息。
我在尝试访问应用程序时遇到此错误:
Caused by: java.lang.UnsupportedOperationException: The application must supply JDBC connections
2015-09-18T09:23:46.533143+00:00 app[web.1]: at org.hibernate.engine.jdbc.connections.internal.UserSuppliedConnectionProviderImpl.getConnection(UserSuppliedConnectionProviderImpl.java:61) ~[org.hibernate.hibernate-core-4.3.10.Final.jar:4.3.10.Final]
2015-09-18T09:23:46.533144+00:00 app[web.1]: at org.hibernate.internal.AbstractSessionImpl$NonContextualJdbcConnectionAccess.obtainConnection(AbstractSessionImpl.java:380) ~[org.hibernate.hibernate-core-4.3.10.Final.jar:4.3.10.Final]
2015-09-18T09:23:46.533146+00:00 app[web.1]: at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:228) ~[org.hibernate.hibernate-core-4.3.10.Final.jar:4.3.10.Final]
2015-09-18T09:23:46.533147+00:00 app[web.1]: at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.getConnection(LogicalConnectionImpl.java:171) ~[org.hibernate.hibernate-core-4.3.10.Final.jar:4.3.10.Final]
2015-09-18T09:23:46.533148+00:00 app[web.1]: at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doBegin(JdbcTransaction.java:67) ~[org.hibernate.hibernate-core-4.3.10.Final.jar:4.3.10.Final]
2015-09-18T09:23:46.533149+00:00 app[web.1]: at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.begin(AbstractTransactionImpl.java:162) ~[org.hibernate.hibernate-core-4.3.10.Final.jar:4.3.10.Final]
我在Hibernate's code and found the UserSuppliedConnectionProviderImpl 类中四处寻找,它似乎完全按照应有的方式工作,因为实现只是抛出了一个异常,这让我相信配置有问题,因为该类没有任何用处,所以我永远不应该到达该代码路径。
我已经关注了how to deploy to heroku上的文档
因此,我的 Procfile 如下:
web: target/universal/stage/bin/myapp -Dhttp.port=${PORT} -DapplyEvolutions.default=false -Ddb.default.driver=org.postgresql.Driver -Ddb.default.url=${DATABASE_URL}
我也尝试过(注意 {})但没有成功
web: target/universal/stage/bin/myapp -Dhttp.port=$PORT -DapplyEvolutions.default=false -Ddb.default.driver=org.postgresql.Driver -Ddb.default.url=$DATABASE_URL
我的 build.sbt 文件包含 postgres 和 hibernate:
libraryDependencies ++= Seq(
javaJdbc,
cache,
javaWs,
javaJpa,
"org.hibernate" % "hibernate-entitymanager" % "4.3.10.Final",
"org.postgresql" % "postgresql" % "9.4-1201-jdbc41" withSources(),
//other stuff
)
我的application.conf 包括以下内容:
db.default.driver=org.postgresql.Driver
db.default.url=${?JDBC_DATABASE_URL}
db.default.username=${?JDBC_DATABASE_USERNAME}
db.default.password=${?JDBC_DATABASE_PASSWORD}
db.default.jndiName=myDS
jpa.default=myDS
我的 persistence.xml 文件(在 conf/META-INF 中)如下(请阅读下文,了解为什么此文件中没有 url/user/password 属性):
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="NoteDS" transaction-type="RESOURCE_LOCAL">
<description>
Persistence unit for the Weldnote Project
</description>
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" />
<!-- Hibernate Properties -->
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
<!-- Show SQL statements -->
<property name="hibernate.show_sql" value="true" />
<!-- Auto Update the database on Entity change -->
<!-- <property name="hibernate.hbm2ddl.auto" value="auto" /> -->
</properties>
</persistence-unit>
根据我从 Heroku 文档(以及 Play 的文档)中读到的内容,Heroku 在环境中提供了DATABASE_URL,这是一种“非标准格式”,但 Play 可以理解。虽然我发现一些报告说它没有直接使用 JPA,因此您必须解析 url 并设置值。我找到了这个 gist explaining how to parse the url 并创建了一个 GlobalSetting 类来做到这一点(我在 application.conf 键下添加了 application.conf application.global=org.example.GlobalSetting。
package org.example;
import java.util.StringTokenizer;
import play.Application;
import play.GlobalSettings;
public class GlobalSetting extends GlobalSettings{
@Override
public void beforeStart(Application app) {
super.beforeStart(app);
String databaseUrl = System.getenv("DATABASE_URL");
StringTokenizer st = new StringTokenizer(databaseUrl, ":@/");
String dbVendor = st.nextToken(); //if DATABASE_URL is set
String userName = st.nextToken();
String password = st.nextToken();
String host = st.nextToken();
String port = st.nextToken();
String databaseName = st.nextToken();
System.out.println(System.getProperty("javax.persistence.jdbc.url"));
System.out.println(System.getProperty("javax.persistence.jdbc.user"));
System.out.println(System.getProperty("javax.persistence.jdbc.password"));
System.out.println(System.getProperty("javax.persistence.jdbc.driver"));
System.setProperty("javax.persistence.jdbc.url", databaseUrl);
System.setProperty("javax.persistence.jdbc.user", userName);
System.setProperty("javax.persistence.jdbc.password", password);
System.setProperty("javax.persistence.jdbc.driver", "org.postgresql.Driver");
System.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
System.out.println(System.getProperty("javax.persistence.jdbc.url"));
System.out.println(System.getProperty("javax.persistence.jdbc.user"));
System.out.println(System.getProperty("javax.persistence.jdbc.password"));
System.out.println(System.getProperty("javax.persistence.jdbc.driver"));
}
}
我知道该类正在运行,因为 println 出现在 Heroku 的日志中。我尝试了许多不同程度的失败变化。我似乎很清楚,这与数据源/数据库的配置有关,但我无法弄清楚任何帮助将不胜感激。
在本地我有一个工作应用程序,但使用 Play 的标准配置(无 DATABASE_URL),我尝试在本地播放环境中匹配 Heroku 的配置,问题似乎是一样的。
我搜索了很多(并在 stackoverflow 上发现了几个具有相同症状的问题,但在我的特定情况下我无法找到可能导致此问题的原因)
编辑:
借助@codefinger 的指点和更多的谷歌搜索,我取得了突破,但我不明白为什么会这样。
在尝试使应用程序在本地运行时,我发现它不适用于 DATABASE_URL,因此我遵循了@codefinger 的建议,问题仍然存在(即运行heroku local web),但如果我有我在 persistence.xml 文件中的属性一切正常(运行activator run)。偶然我在 GlobalSettings 文件中尝试了以下内容:
System.setProperty("javax.persistence.jdbc.url", System.getenv("JDBC_DATABASE_URL"));
System.setProperty("javax.persistence.jdbc.user", System.getenv("JDBC_DATABASE_USERNAME"));
System.setProperty("javax.persistence.jdbc.password", System.getenv("JDBC_DATABASE_PASSWORD"));
System.setProperty("javax.persistence.jdbc.driver", "org.postgresql.Driver");
System.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
System.setProperty("hibernate.connection.driver_class", "org.postgresql.Driver");
System.setProperty("hibernate.connection.url", System.getenv("JDBC_DATABASE_URL"));
System.setProperty("hibernate.connection.username", System.getenv("JDBC_DATABASE_USERNAME"));
System.setProperty("hibernate.connection.password", System.getenv("JDBC_DATABASE_PASSWORD"));
通过传递javax.persistence.* AND hibernate.connection.* 连接属性显然它现在可以访问数据库。
但是我似乎无法理解在本地运行时只使用javax.persitence.* 文件上的javax.persitence.* 属性它工作正常。
我正在继续我的实验,试图找到合适的配置。
【问题讨论】:
标签: java hibernate jpa heroku playframework