如何在不依赖数据库的情况下启动Spring Boot应用程序?

37

我的应用程序使用"Spring-boot + Hibernate4 + mysql"。其中一个要求是,即使数据库宕机,我的Sprint-boot应用程序也应该能够启动。当前,当我尝试在DB未启动时启动spring boot应用程序时,会出现以下异常。

我进行了大量研究,并发现这个异常与hibernate.temp.use_jdbc_metadata_defaults属性有关。

我尝试在spring boot的"application.yml"文件中设置它,但是这个属性的值在运行时没有被反映。

异常堆栈跟踪:

2014-05-25 04:09:43.193  INFO 59755 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {4.0.4.Final}
2014-05-25 04:09:43.250  WARN 59755 --- [           main] o.h.e.jdbc.internal.JdbcServicesImpl     : HHH000342: Could not obtain connection to query metadata : Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
2014-05-25 04:09:43.263  INFO 59755 --- [           main] o.apache.catalina.core.StandardService   : Stopping service Tomcat

Error starting ApplicationContext. To display the auto-configuration report enabled debug logging (start with --debug)


Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.HibernateException: Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1553)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:973)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:750)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:120)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:648)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:311)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:909)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:898)
    at admin.Application.main(Application.java:36)
Caused by: org.hibernate.HibernateException: Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set
    at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.determineDialect(DialectFactoryImpl.java:104)
    at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.buildDialect(DialectFactoryImpl.java:71)
    at org.hibernate.engine.jdbc.internal.JdbcServicesImpl.configure(JdbcServicesImpl.java:205)
    at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:89)
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:206)
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:178)
    at org.hibernate.cfg.Configuration.buildTypeRegistrations(Configuration.java:1885)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1843)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:850)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:843)
    at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:399)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:842)
    at org.hibernate.jpa.HibernatePersistenceProvider.createContainerEntityManagerFactory(HibernatePersistenceProvider.java:150)
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:336)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1612)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1549)
    ... 15 more

应用程序配置文件 application.yml:

spring:   
  jpa:
show-sql: true
hibernate:
  ddl-auto: none
  naming_strategy: org.hibernate.cfg.DefaultNamingStrategy
  temp:
    use_jdbc_metadata_defaults: false
5个回答

62

这确实是一个难题。

经过大量的研究和调试spring-boot、spring、hibernate、tomcat pool等,我认为这将为那些尝试实现这种要求的人节省很多时间。

下面是实现此要求所需的设置:

  1. 即使DB宕机或不存在DB,Spring Boot应用程序也会正常启动。
  2. 应用程序会在DB上线时即时获取连接,这意味着无需重新启动Web服务器或重新部署应用程序。
  3. 如果DB从运行状态下线并重新上线,则无需启动Tomcat或重新部署应用程序。

application.yml:

spring:
  datasource:
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/schema
    username: root
    password: root
    continueOnError: true
    initialize: false
    initialSize: 0
    timeBetweenEvictionRunsMillis: 5000
    minEvictableIdleTimeMillis: 5000
    minIdle: 0

  jpa:
    show-sql: true
    hibernate:
      ddl-auto: none
      naming_strategy: org.hibernate.cfg.DefaultNamingStrategy
    properties:
      hibernate:   
        dialect: org.hibernate.dialect.MySQL5Dialect
        hbm2ddl:
          auto: none
        temp:
          use_jdbc_metadata_defaults: false

这个真的为我节省了很多时间。谢谢伙计。 - Shishir Kumar
感谢您的代码。我必须在 EclipseLink 中执行相同的操作,只需在 persistence.xml 中添加 <property name="eclipselink.validation-only" value="true"/> 即可完成。 - mdrg
1
现在提到的道具已经过时了。@ripu,你知道有哪些新属性吗? - Vinay Prajapati
我所需要的唯一设置是 spring.jpa.database-platform - pacoverflow
如果我一开始没有 JDBC URL,因为我是动态创建数据库,那该怎么办? - Brayan Loayza

10

我在此回答并关闭你跨发的问题

任何JPA实现(如Hibernate)的“本地”属性都可以使用spring.jpa.properties前缀进行设置,如此处所述

我还没有深入研究实际问题,但是为了回答这个特定问题,您可以按以下方式设置那个Hibernate键

spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults

1
谢谢。这修复了设置"use_jdbc_metadata_defaults"属性的问题。但是,如果您看到我的帖子,实际问题是“即使数据库宕机,启动sprint-boot应用程序也应该能够启动”,仅通过设置此属性无法解决。 - Ripu Daman
只是为了明确,这与Spring Boot无关。Boot仅提供一种机制来配置基础的Hibernate基础设施,并且如果您自己进行配置(即手动操作),则会遇到完全相同的问题。感谢分享配置! - Stephane Nicoll

5

仅添加以下内容对我有效:

spring.jpa.properties.hibernate.dialect: org.hibernate.dialect.Oracle10gDialect

只需将最后一部分替换为您的数据库方言。


0

这个解决方案对我非常有用。谢谢。 我使用的文件是“application.properties”,包含以下几行:

    app.sqlhost=192.168.10.11
    app.sqlport=3306
    app.sqldatabase=logs

    spring.main.web-application-type=none

    # Datasource
    spring.datasource.url=jdbc:mysql://${app.sqlhost}:${app.sqlport}/${app.sqldatabase}
    spring.datasource.username=user
    spring.datasource.password=password
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
    spring.jpa.properties.hibernate.hbm2dll.auto = none
    spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false

    spring.datasource.continue-on-error=true
    spring.datasource.initialization-mode=never

    spring.datasource.hikari.connection-timeout=5000
    spring.datasource.hikari.idle-timeout=600000
    spring.datasource.hikari.max-lifetime=1800000
    spring.datasource.hikari.initialization-fail-timeout= -1

    spring.jpa.hibernate.use-new-id-generator-mappings=true
    spring.jpa.hibernate.ddl-auto=none

    spring.jpa.show-sql=true

    spring.output.ansi.enabled=always

但是你不能在类级别上使用 @Transactional 注释

@Service
//@Transactional  //do not use to touch the Repository
@EnableAsync
@Scope( proxyMode = ScopedProxyMode.TARGET_CLASS )
public class LogService {
.... }

@Async
@Transactional  // you can use at function level
public void deleteLogs(){
    logRepository.deleteAllBy ...
}

-1

添加以下配置应该可以解决问题:

spring.jpa.database-platform: org.hibernate.dialect.MySQL5Dialect


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接