[SPRING] Spring Boot에서 Heroku Postgres에 연결하기
SPRINGSpring Boot에서 Heroku Postgres에 연결하기
나는 JPA / Hibernate를 사용하는 Spring Boot app에서 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;
}
}
나는 프로필을 사용하고 있는데, 나는 원했던 부분과 잘 어울리는 것 같다 : Heroku SPRING_PROFILES_ACTIVE는 postgres로 설정되었고, 지역 개발 spring.profiles.active는 H2 메모리 내장 데이터베이스 (여기서는 생략)를 사용하는 h2이다. 이 접근 방식은 정상적으로 작동하는 것 같습니다.
application-postgres.properties (프로필 관련 등록 정보)에서
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.datasource.driverClassName=org.postgresql.Driver
Tomcat의 DataSource는 기본 의존성이 포함되어 있기 때문에 좋은 옵션처럼 보였습니다. Spring Boot 참조 가이드는 다음과 같이 말합니다 :
(나는 또한 봄 부팅과 함께 사용되는 Commons DBCP에서 BasicDataSource를보고있다.하지만 나에게 이것은 Commons DBCP를 기본 의존성이 포함되지 않는 가장 깨끗한 선택처럼 보이지 않는다. 그리고 일반적으로 나는 Apache Commons가 정말로 할 수 있는지, 2015 년에 Postgres에 연결하는 것이 좋습니다 ... 또한 Heroku 문서는 "Spring의 BasicDataSource"시나리오를 제공합니다. Spring 자체에서는 이러한 클래스가 보이지 않기 때문에 Commons DBCP를 참조합니다.)
종속성 :
<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>
현재 상태 : "driverClassName 속성이 null이므로 JDBC 드라이버를로드하지 않음"으로 실패 함 :
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
로그에서 나는 내 postgresDataSource가 잘 호출되는 것을 볼 수있다. PostgreSQLDialect가 사용 중입니다 (이 기능을 사용하지 않으면 "hibernate.dialect가 설정되지 않았을 때 DialectResolutionInfo에 대한 액세스가 null 일 수 없습니다").
내 특정 질문
해결법
-
==============================
1.안정적인 방식으로 데이터베이스 연결을 작동 시키려면 질문에서 설명한 설치에서 두 가지가 누락되었습니다.
안정적인 방식으로 데이터베이스 연결을 작동 시키려면 질문에서 설명한 설치에서 두 가지가 누락되었습니다.
그래서, 내 DataSourceConfig의 고정 버전 :
@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(); org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource(); dataSource.setDriverClassName("org.postgresql.Driver"); dataSource.setUrl(dbUrl); dataSource.setUsername(username); dataSource.setPassword(password); dataSource.setTestOnBorrow(true); dataSource.setTestWhileIdle(true); dataSource.setTestOnReturn(true); dataSource.setValidationQuery("SELECT 1"); return dataSource; } }
application-postgres.properties 파일에서만 다음을 수행합니다.
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
자, 내가 가진 두 가지 문제점은 Tomcat (org.apache.tomcat.jdbc.pool)의 DataSource에 한정 될 수 있습니다. 분명히 BasicDataSource (Commons DBCP)는 더 현명한 기본값을가집니다. 그러나이 질문에서 언급했듯이, 나는 기본적으로 Spring Boot와 함께 제공되는 것을 사용했다. 특히 참조 가이드에서 강력하게지지를 받았다.
경쟁 / 단순 / 더 나은 솔루션에 개방적입니다. 특히 질문 끝에 2-4 번 문제를 해결할 수 있다면 게시 해주십시오!
업데이트 : JDBC_DATABASE_ *를 사용하면 위의 답변보다 훨씬 간단하다는 것에 유의하십시오. 오랫동안 나는 DATABASE_URL이 선호되어야한다는 인상하에 있었지만, 요즘에는 더 이상 확신 할 수 없습니다.
-
==============================
2.가장 단순한 Spring Boot / Heroku / Hibernate 설정
가장 단순한 Spring Boot / Heroku / Hibernate 설정
항상 거기에있는 DATABASE_URL을 제외하고, Heroku는 런타임에 3 개의 환경 변수를 생성합니다. 그들은:
JDBC_DATABASE_URL JDBC_DATABASE_USERNAME JDBC_DATABASE_PASSWORD
아시다시피 스프링 부트는 application.properties 파일에서 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 / Postgres Dependencies
제 경우에는 Hibernate (PostgreSQL과 함께 spring-boot-starter-jpa에 번들되어 있습니다. 그래서 build.gradle에 올바른 의존성이 필요했습니다 :
dependencies { compile("org.springframework.boot:spring-boot-starter-data-jpa") compile('org.postgresql:postgresql:9.4.1212') }
-
==============================
3.나는 모든 대답을 읽었지만 조닉이 찾고 있던 것을 찾지 못했습니다.
나는 모든 대답을 읽었지만 조닉이 찾고 있던 것을 찾지 못했습니다.
대부분의 사람들이 Spring Boot & Heroku에서 사용하기를 원하는 개발 프로세스에는 테스팅 및 빠른 개발 사이클을위한 로컬 H2 인 메모리 데이터베이스와 Heroku에서 스테이징 및 프로덕션을위한 Heroku Postgres 데이터베이스가 포함됩니다.
단계별로해야 할 일에 대해 살펴 보겠습니다. Postgres에 대한 완벽한 Heroku 배포 및 구성을 제공하는 예제 프로젝트가 있습니다. 직접 테스트하려는 경우에는 완전성을 위해서만 github.com/jonashackt/spring-boot-vuejs하십시오.
다음과 같은 종속성이 필요합니다.
<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 환경 변수에는 Config Vars라는 이름이 지정됩니다. 우리가해야 할 일은 환경 변수를 구성하는 것입니다. 우리는 정확한 것을 필요로합니다. 그러므로 https://data.heroku.com/로 가보십시오. (기본 동작 인 Heroku 앱용으로 이미 구성된 Postgres 데이터베이스가 있다고 가정합니다).
이제 응용 프로그램의 해당 Datastore를 클릭하고 설정 탭으로 전환하십시오. 그런 다음 자격 증명보기 ...를 클릭하면 다음과 비슷한 화면이 나타납니다.
이제 새 브라우저 탭을 열고 Heroku 응용 프로그램의 설정 탭으로 이동하십시오. Reveal Config Vars를 클릭하고 다음 환경 변수를 만듭니다.
Heroku에서 이것은 다음과 같아야합니다 :
이제 그게 다야! Heroku 앱은 구성 변수를 변경할 때마다 다시 시작되므로 앱이 로컬에서 H2를 실행해야하고 Heroku에 배포 할 때 PostgreSQL과 연결할 준비가되어 있어야합니다.
주목할 수 있듯이, 우리는 pom.xml에 tomcat-jdbc 의존성을 추가하고 환경 변수로 SPRING_DATASOURCE_TYPE = org.apache.tomcat.jdbc.pool.DataSource를 구성했습니다. 이 말에 관한 문서에는 약간의 힌트 만 있습니다.
Spring Boot 2.x 표준 HikariCP 대신 DataSource를 풀링하는 Tomcat으로 다시 전환 한 몇 가지 이유가 있습니다. 이미 설명했듯이 spring.datasource.url을 지정하지 않으면 Spring은 PostgreSQL 대신 내장 된 im-memory H2 데이터베이스를 autowire하려고합니다. 그리고 히카리 문제는 spring.datasource.jdbc-url 만 지원한다는 것입니다.
둘째, Hikari에 표시된대로 Heroku 구성을 사용하려고하면 (SPRING_DATASOURCE_TYPE을 생략하고 SPRING_DATASOURCE_URL을 SPRING_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
그래서 HikariCP와 함께 Heroku & Postgres에서 Spring Boot 2.x를 사용하지는 않았지만 Tomcat JDBC로 - 그리고 나는 또한 선행 기술 된 로컬 H2 데이터베이스를 포함하는 개발 프로세스를 제동하고 싶지 않습니다. 기억하세요 : 우리는 JPA / Hibernate를 사용하는 Spring Boot app에서 Heroku Postgres에 연결하는 가장 단순하고 청결한 방법을 찾고있었습니다!
-
==============================
4.DATABASE_URL을 구문 분석하는 대신 spring.datasource.url로 JDBC_DATABASE_URL을 사용해보십시오.
DATABASE_URL을 구문 분석하는 대신 spring.datasource.url로 JDBC_DATABASE_URL을 사용해보십시오.
DATABASE_URL을 구문 분석하는 것이 좋지만 작동시키지 못하면 JDBC_DATABASE_URL이 정상적이어야합니다.
-
==============================
5.이것은 Heroku가 제공하는 샘플 Java 응용 프로그램으로 Postgres 문제를 검색 할 때 가장 많이 사용되는 답변입니다.
이것은 Heroku가 제공하는 샘플 Java 응용 프로그램으로 Postgres 문제를 검색 할 때 가장 많이 사용되는 답변입니다.
이것들이 작동하도록했던 단계들입니다 (Win 7).
1.) 프로덕션 서버 application.properties 파일에는 시스템 환경이 포함됩니다 (이 파일이 커밋되었는지 확인하십시오)
spring.datasource.url=${JDBC_DATABASE_URL} spring.datasource.username=${JDBC_DATABASE_USERNAME} spring.datasource.password=${JDBC_DATABASE_PASSWORD}
2.) 이제 git update-index --assume-unchanged를 실행합니다. \ src \ main \ resources \ application.properties
3.) 로컬 application.properties가 하드 코드되도록 변경하십시오. heroku run env를 실행하여 원시 값을 볼 수 있습니다.
spring.datasource.url=jdbc://.. spring.datasource.username=XYZ spring.datasource.password=ABC
이것이 내 응용 프로그램의 로컬 복사본을 가져와야 만했습니다. 누구든지 더 나은 방법을 발견한다면 공유하십시오!
-
==============================
6.
@Configuration @Component public class HerokuConfigCloud { private static final Logger logger = LoggerFactory.getLogger(HerokuConfigCloud .class); @Bean() //@Primary this annotation to be used if more than one DB Config was used. In that case, // using @Primary would give precedence to a the particular "primary" config class @Profile("heroku") public DataSource dataSource( @Value("${spring.datasource.driverClassName}") final String driverClass, @Value("${spring.datasource.url}") final String jdbcUrl, @Value("${spring.datasource.username}") final String username, @Value("${spring.datasource.password}") final String password ) throws URISyntaxException { return DataSourceBuilder .create() .username(username) .password(password) .url(url) .driverClassName(driverClass) .build(); } }
-
==============================
7.이 작업을 쉽게 수행 할 수 있도록 라이브러리를 만들었습니다. https://github.com/vic-cw/heroku-postgres-helper
이 작업을 쉽게 수행 할 수 있도록 라이브러리를 만들었습니다. https://github.com/vic-cw/heroku-postgres-helper
빌드 스크립트와 응용 프로그램 논리에서 데이터베이스에 액세스해야하는 경우이 방법이 더 유용합니다. 왜 여기 있는지보십시오.
build.gradle :
// If using connection string in build script: buildscript { repositories { maven { url 'https://jitpack.io' } } dependencies { classpath 'com.github.vic-cw:heroku-postgres-helper:0.1.0' } } import com.github.viccw.herokupostgreshelper.HerokuPostgresHelper; // Use connection string in build script: flyway { url = HerokuPostgresHelper.getDatabaseJdbcConnectionString() driver = 'org.postgresql.Driver' } // If using connection string inside application logic: repositories { maven { url 'https://jitpack.io' } } dependencies { compile group: 'com.github.vic-cw', name: 'heroku-postgres-helper', version: '0.1.0' }
자바 애플리케이션 코드 :
import com.github.viccw.herokupostgreshelper.HerokuPostgresHelper; ... String databaseConnectionString = HerokuPostgresHelper.getDatabaseJdbcConnectionString();
from https://stackoverflow.com/questions/33633243/connecting-to-heroku-postgres-from-spring-boot by cc-by-sa and MIT license