Solucionado (ver solução)
Solucionado
(ver solução)
3
respostas

Mapeia mas mas hibernate não funciona

Não consegui fazer a integração com os dois bancos de dados! Ele sobe a aplicação porem não consigo utilizar o banco de dados localmente nem com o heroku

https://imgur.com/a/oTErc

EDIT Verifiquei que o erro ocorre quando eu coloco o @Profile no Datasource e Properties

JPAConfiguration

@EnableTransactionManagement
public class JPAConfiguration{

  /**
   * DataSource definition for database connection. Settings are read from
   * the application.properties file (using the env object).
   */
  @Bean
  @Profile("dev")
  public DataSource dataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setDriverClassName("db.driver");
    dataSource.setUrl("db.url");
    dataSource.setUsername("db.username");
    dataSource.setPassword("db.password");
    return dataSource;
  }
  @Bean
  @Profile("dev")
  public Properties additionalProperties() {
      Properties additionalProperties = new Properties();
        additionalProperties.put( "hibernate.dialect", "hibernate.dialect");
        additionalProperties.put("hibernate.show_sql", "hibernate.show_sql");
        additionalProperties.put("hibernate.hbm2ddl.auto", "hibernate.hbm2ddl.auto");
        return additionalProperties;
  }

  @Bean
  public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource datasource, Properties additionalProperties) {
      LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
        factoryBean.setPackagesToScan("entitymanager.packagesToScan");
        factoryBean.setDataSource(datasource);

        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        factoryBean.setJpaVendorAdapter(vendorAdapter);
        factoryBean.setJpaProperties(additionalProperties);

        return factoryBean;
  }


  /**
   * Declare the transaction manager.
   */
  @Bean
  public JpaTransactionManager transactionManager() {
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(entityManagerFactory.getObject());
    return transactionManager;
  }

  /**
   * PersistenceExceptionTranslationPostProcessor is a bean post processor
   * which adds an advisor to any bean annotated with Repository so that any
   * platform-specific exceptions are caught and then rethrown as one
   * Spring's unchecked data access exceptions (i.e. a subclass of 
   * DataAccessException).
   */
  @Bean
  public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
    return new PersistenceExceptionTranslationPostProcessor();
  }  

  @Autowired
  private LocalContainerEntityManagerFactoryBean entityManagerFactory;

JPAProductionConfiguration

@Profile("prod")
public class JPAProductionConfiguration {

    @Autowired
    private Environment environment;

    @Bean
    public Properties additionalProperties() {
        Properties props = new Properties();
        props.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
        props.setProperty("hibernate.show_sql", "true");
        props.setProperty("hibernate.hbm2ddl.auto", "update");
        return props;
    }

    @Bean
    public DataSource dataSource() throws URISyntaxException {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("org.postgresql.Driver");
        // usuario:senha@host:port/path
        URI dbUrl = new URI(environment.getProperty("DATABASE_URL"));

        dataSource.setUrl("jdbc:postgresql://"+dbUrl.getHost()
            +":"+dbUrl.getPort()+dbUrl.getPath());
        dataSource.setUsername(dbUrl.getUserInfo().split(":")[0]);
        dataSource.setPassword(dbUrl.getUserInfo().split(":")[1]);

        return dataSource;
    }

}
3 respostas
solução!

Fala Luís, tudo bem ?

Perceba que nos logs de inicialização do Spring Boot ele diz que não foi definido profile para o start da aplicação. O que significa que seus beans definidos sobre profiles diferentes do default (default == beans não anotados com nenhum profile) não serão levados em conta pela application context.

Perceba também que no aditionalProperties() da configuração de dev as chaves estão repetidas sendo usadas também como valor.

Tente mudar para algo como :

@Bean
  @Profile("dev")
  public Properties additionalProperties() {
      Properties additionalProperties = new Properties();
        additionalProperties.put( "hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect"); // ou outro dialeto mais específico para sua infra
        additionalProperties.put("hibernate.show_sql", "true");
        additionalProperties.put("hibernate.hbm2ddl.auto", "update");
        return additionalProperties;
  }

Assim como a configuração do data source de dev não vai resolver automaticamente a string "db.driver" em setDriverClassName("db.driver"); na referencia do DataSource.

Você precisaria seguir uma estratégia parecida com a aplicada na classe de configuração de produção. Injetar Environment e pegar como propriedades, visto que o Spring Boot ja deixa o conteúdo do application.properties disponível.

Mas, tem uma coisa bem legal que dá pra fazer com Spring Boot pra evitar toda essa burocracia.

O Spring Boot suporta que você tenha multiplos arquivos de application.properties separados por perfis. Assim poderiamos ter o seguintes.

src/main/resources
    -- application.properties
    -- application-prod.properties

E você poderia a partir das chaves de propriedades definidas pela documentação do boot já passar as informações para a classe de auto configuração de DataSource que ele já traz pra você. O que significa que não será mais necessário escrever código java de configuração desses beans (mesmo que isso ainda seja permitido e funcione normalmente)

Exemplo:

application.properties (arquivo de properties padrão - ambiente de desenvolvimento)

## Suas informações de ambiente de dev aqui

# setting profile
spring.profiles.active=dev # não necessário, mas como demonstrativo caso tenha outras configurações programáticas de beans separados por profiles

# data source #com infos da base de dev
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/rom_dev?createDatabaseIfNotExist=true
spring.datasource.username=root
spring.datasource.password=

# hibernate properties
spring.jpa.hibernate.ddl-auto=update

application-prod.properties

#spring boot properties

# data source
spring.datasource.driver-class-name=com.mysql.jdbc.Driver // ou fully qualified name de outra classe que define seu driver jdbc usado em produção
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}
spring.datasource.url=jdbc:mysql://${DB_HOST}:${DB_HOST_PORT}/${DB_NAME}?createDatabaseIfNotExist=true
spring.jpa.hibernate.ddl-auto=update

Aqui vemos que o Spring Boot já da acesso a variáveis de ambiente do sistema (que você pode setar a vontade na máquina no heroku) através de ${NOME_DA_VARIAVEL} como conteúdo de qualquer chave do properties.

Ele também usa como padrão o nome (depois do hífen) no arquivo como padrão de profile utilizado. Agora bastaria você passar como um VM argument no procfile do heroku a informação sobre o perfil de prod.

Exemplo procfile:

web: java -Dserver.port=$PORT -Dspring.profiles.active=prod -jar target/*.jar

Espero ter ajudado. Abraço!

Top ajudou bastante sua explicação consegui entender melhor essa parte do spring boot.

Achei que o application.properties era apenas pra definir propriedades que queriamos, não sabia que dava para definir propriedades já inseridas pelo Spring.

Inseri o spring.profiles.active=dev e funcional devia estar dando algum conflito com algum Bean.

Valeu ajudou bastante

Boa Luís! Que bom que resolveu e deu certo a configuração dos seus beans.

Mas lembre-se, a ideia central do projeto do Spring Boot é justamente tirar da sua mão a responsabilidade de escrever esses códigos java que definem configurações dos seus beans. Procure pela classe chamada DataSourceAutoConfiguration da api do Spring Boot. Lá você vai ver que já está escrito todo o código java necessário pra configurar seus data sources. Você só precisa ter nos application.properties as propriedades do banco (como no exemplo usado anteriormente) sem escrever mais nenhuma instrução java pra funcionar a configuração. O Spring Boot já vai buscar as informações do banco no arquivo properties e aplicar a configuração que já vem convencionada.

É só aproveitar. Spring Boot é vida! =)

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software