【问题标题】:Spring Web Application: doing something on startup (initialization)Spring Web Application:在启动时做某事(初始化)
【发布时间】:2025-12-11 10:15:01
【问题描述】:

我想在启动时从一个文本文件中填充我的数据库的一些表,我希望只有在我的应用程序启动时才调用我的初始化方法。

我在 MySQL 中使用 Spring (+MVC) 和 Hibernate。

我该怎么办?

【问题讨论】:

标签: spring hibernate spring-mvc initialization startup


【解决方案1】:

您可以创建一个应用程序侦听器,它专为此类需求而设计。在这种情况下,它将在每次启动(或刷新)上下文时执行。

@Component
public class DatabaseFillerOnStartup implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        ...
    }
}

【讨论】:

  • 正是我想要做的自我诊断。谢谢!
  • 这应该是答案... :)
  • 但这也将在测试用例中调用,并且 DB 不适用于测试用例。如何解决这种情况?
  • @Pokuri:你有几个选择。 1) 不要在@Configuration 中声明这个bean 用于测试,就像你可能不声明@Controller@Scheduled 任务一样。 2)在这个方法中添加一些条件逻辑,也许分析堆栈跟踪以了解您是否在 jUnit 测试中。显然,首先是首选。
【解决方案2】:

Hibernate 提供了一种方法来添加一些带有 sql 语句的文件,这些语句将在启动时执行。

参数为hibernate.hbm2ddl.import_files

@见Hibernate Reference: Chapter 3.4. Optional configuration properties

  • 表 3.7。其他属性
  • hibernate.hbm2ddl.import_files:

包含 SQL DML 的可选文件的逗号分隔名称 在 SessionFactory 创建期间执行的语句。这很有用 用于测试或演示:例如通过添加 INSERT 语句 可以使用最少的数据集填充数据库 部署。

文件顺序很重要,给定文件的语句在执行之前 以下文件的陈​​述。这些陈述仅 如果创建了模式,即如果设置了 hibernate.hbm2ddl.auto,则执行 创建或创建-删除。

例如/humans.sql,/dogs.sql

我喜欢一些提示,这可能仅在休眠以“创建”模式启动时才有效。但我不确定。

【讨论】:

  • 非常有用。这不是问题本身的答案,而是....这正是我所需要的!谢谢!但是,我不能让 import_files 工作 :( 而不是我在我的类路径中放了一个“import.sql”,它可以完美地执行!
【解决方案3】:

在 bean 内的某处使用 postconstruct 注解:

@PostConstruct
public void init() {
     //startup logic here
}

使用配置 bean 可能(设计)有意义,但它可以是任何 bean。

【讨论】:

  • 好的,所以正确的方法可以是制作“Initializator”单例和@PostConstruct 方法?谢谢! :)
  • 这不适用于启动 AsyncTasks。使用以下 sinuhepop 的推荐 - *.com/a/9680800/1019307
【解决方案4】:

两个选项,

首先:让hibernate在每次服务启动时创建你的ddl(仅适用于本地或开发环境)

<bean id="hibernateVendor" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
      p:showSql="false"
      p:generateDdl="true"/>

或者在 spring 中创建一个带有 init-lazy false 的 Bean,并在其中添加创建数据库的逻辑,如果你没有它或者注入你的脚本,或者做任何你想做的事情。

 <bean id="bootstrapStartup" class="com.tscompany.rest.bootstrap.BootstrapStartup" lazy-init="false" init-method="init"/>

【讨论】:

    【解决方案5】:

    您可以在根上下文配置中创建一些 bean - 比如

    <bean id="someBean" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="someProperty">
            ... description of the property
        </property>
        <property name="targetMethod" value="methodName" />
    </bean>
    

    因此 - 在应用程序启动方法“methodName”将被调用。我们以这种方式实施了数据库升级。

    【讨论】:

      【解决方案6】:

      如果您将hibernate.hbm2ddl.auto 属性设置为createcreate-drop,那么最简单的方法是使用包含SQL 语句的SQL 文件名设置hibernate.hbm2ddl.import_files 属性,以将初始数据加载到数据库中架构,例如初始应用程序用户。

      以下是我在DatabaseConfig 类中的示例方法。它使用 SQL 文件名 import_initial_data.sql 设置 hibernate.hbm2ddl.import_files 属性,其中包含 SQL 插入语句以将我的初始数据加载到数据库架构中。

         @Bean
         public LocalSessionFactoryBean hibernate5SessionFactoryBean(){
            LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
            localSessionFactoryBean.setDataSource((DataSource) appContext.getBean("DataSource"));
            localSessionFactoryBean.setAnnotatedClasses( AppUser.class );
            Properties properties = new Properties();
            properties.put( "hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
            properties.put("hibernate.hbm2ddl.auto","create-drop");
            properties.put("hibernate.hbm2ddl.import_files", "import_initial_data.sql");
            properties.put("hibernate.show_sql","true");
            localSessionFactoryBean.setHibernateProperties(properties);
            return localSessionFactoryBean;
         }
      

      这是我在model 包中的AppUser.java

      package com.beniregev.model;
      
      import lombok.AccessLevel;
      import lombok.AllArgsConstructor;
      import lombok.NoArgsConstructor;
      import javax.persistence.*;
      
      @Entity
      @NoArgsConstructor(access = AccessLevel.PUBLIC)
      @AllArgsConstructor(access = AccessLevel.PUBLIC)
      public class AppUser {
         @Id
         @GeneratedValue(strategy = GenerationType.IDENTITY)
         private int id;
         @Column(nullable = false, unique = true)
         private String userName;
         @Column(nullable = false)
         private String password;
      
         public AppUser(String userName, String password) {
            this.userName = userName;
            this.password = password;
         }
      }
      

      lombok 的 Maven 依赖项:

      <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
         <version>1.16.6</version>
         <scope>provided</scope>
      </dependency>
      

      我在resources 目录中的import_initial_data.sql 文件:

      INSERT INTO appuser(username, password) VALUES ('jesus', 'christ');
      INSERT INTO appuser(username, password) VALUES ('mary', 'virgin');
      INSERT INTO appuser(username, password) VALUES ('josef', 'who?');
      INSERT INTO appuser(username, password) VALUES ('jeremaia', 'profet');
      COMMIT;
      

      以及*SELECT * FROM appuser;*的结果:

      【讨论】:

        最近更新 更多