如何在应用程序启动时运行SQL脚本并获取数据?

38

我正在开发一个Spring Boot应用程序。目前我的一些配置是硬编码的(例如Hystrix属性)。

因此,我希望在应用程序启动时或之后立即获取这些配置。

使用Spring Boot是否可能实现这一点?我的意思是在启动时运行SQL脚本并获取数据。

应该如何检索和存储应用程序中的属性/配置?

我正在使用MyBatis和Oracle数据库。


1
将它们放入application.yml文件中,并使它们与配置文件相关联。 - duffymo
我有这样的想法,但目前我想从数据库中获取值 :) - Laurynas
7个回答

70
默认情况下,Spring-Boot会加载data.sql和/或data-${platform}.sql
然而,请记住脚本将在每次启动时加载,所以我认为(至少对于生产环境来说)更合理的做法是,数据库中已经存在这些值,而不是在每次启动时重新插入。个人而言,我只在使用内存数据库进行测试/开发时才使用数据库初始化。尽管如此,这是Spring-Boot提供的功能。
来源:spring-boot-howto-database-initialization

Spring JDBC具有数据源初始化功能。Spring Boot默认启用它,并从标准位置schema.sql和data.sql(在类路径的根目录下)加载SQL。此外,Spring Boot还会加载schema-${platform}.sql和data-${platform}.sql文件(如果存在)。

src/main/resources/data-oracle.sql:

insert into...
insert into...
  • 您可以使用以下代码定义平台:spring.sql.init.platform=oracle
  • 您可以更改要加载的 SQL 脚本的名称:spring.sql.init.data-locations=myscript.sql
  • 除了 data.sql,Spring Boot 还会加载 schema.sql(在 data.sql 之前)。
  • 您还可以在 data.sql 中使用“更新或插入”逻辑:oracle sql: update if exists else insert

我不需要插入数据。我需要从数据库中获取数据 :) - Laurynas
看一下Spring Batch的工作原理,启动时不需要运行选择命令,我看不出有什么意义。如果你想在启动时加载数据,最好使用批处理。@Laurynas - tero17
1
你好 @alexbt该用户发布的标题有点误导。他希望在应用程序启动时从数据库中加载配置(而不是创建和初始化模式)。 - Philip Dilip
p.s. 要加载自定义文件名,您可以设置 spring.datasource.schema - ch271828n
1
配置属性 'spring.datasource.platform' 和 'spring.datasource.data' 已被弃用。请改用 spring.sql.init.platform=h2,spring.sql.init.data-locations=classpath:/data.sql。 - VirtualLogic
Spring文档链接似乎不再起作用,可能是因为文档已经更新。https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.data-initialization.using-basic-sql-scripts 是新链接。 - Akki

14

对我起作用的是使用 DataSourceInitializer

@Bean
public DataSourceInitializer dataSourceInitializer(@Qualifier("dataSource") final DataSource dataSource) {
    ResourceDatabasePopulator resourceDatabasePopulator = new ResourceDatabasePopulator();
    resourceDatabasePopulator.addScript(new ClassPathResource("/data.sql"));
    DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();
    dataSourceInitializer.setDataSource(dataSource);
    dataSourceInitializer.setDatabasePopulator(resourceDatabasePopulator);
    return dataSourceInitializer;
}
在初始化期间设置数据库并在销毁期间清除数据库。 https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/datasource/init/DataSourceInitializer.html

1
该用户发布的标题有点误导人,他希望在应用程序启动时从数据库中加载配置(而不是创建和初始化模式)。 - Philip Dilip
@PhilipDilip 这个解决方案可以用来执行脚本,不仅限于初始化模式。 - Emeric

10

如果希望在启动后从 sql 脚本中加载数据,可以使用 ResourceDatabasePopulator 类对象如下所示。

import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;

import javax.sql.DataSource;

@Component
public class InitializeData {

    @Autowired
    private DataSource dataSource;

    @EventListener(ApplicationReadyEvent.class)
    public void loadData() {
            ResourceDatabasePopulator resourceDatabasePopulator = new ResourceDatabasePopulator(false, false, "UTF-8", new ClassPathResource("data.sql"));
        resourceDatabasePopulator.execute(dataSource);
    }
}

它可以轻松地从 SQL 文件中加载数据,不用担心 SQL 文件中的错误语句,因为它会被忽略。


3
如果您想根据某些业务逻辑插入数据,我建议您使用事件监听器。因此,在应用程序启动时,“OnApplicationEvent”方法将自动调用,因为它被注释为@EventListener。
另外,对于您的情况,您只需使用存储库对象获取数据即可。
以下是一个示例:
@Component
public class OnApplicationStartUp {

   @Autowired
   private ServiceRepository repository;


   @EventListener
   public void onApplicationEvent(ContextRefreshedEvent event) {

       //Write your business logic here.
       if (repository.findAll().size() <= 0) {
           preloadData();
       }else{
           fetchData();
       }
   }

    private void preloadData() {

       List<Service> services = new ArrayList<>();
       Service someService= new Service("name", "type");
       services.add(someService);
       ...
       ...
       repository.saveAll(services);
   }
}

1
如果你从 application.properties 文件中获取信息,可以使用 Environment 类。就像这样:
Autowired
private Environment environment;
...
environment.getProperty("propertyName")

或者你可以定义自己的属性文件。然后你可以使用@PropertySource(name = "myProperties", value = "example.properties")注释从中获取内容。
你需要使用@Value注释来从你定义的属性文件中获取特定的值。
@Value("${propertyNameInYourPropertFile}")
private String url;

如果您希望在应用程序刚启动时开始某些操作,您可以在一个方法之前使用此方法。

@EventListener(ApplicationReadyEvent.class)

但需要使用@Service或@Component注释,这个类具有该方法。

总之,您可以使用此功能。

example.properties:

url=yourValue
userName=yourDBUserName
password=yourDBPassword

例子类:

@Service
@PropertySource(name = "myProperties", value = "example.properties")
public class Start{

    @Value("${url}")
    private String url;

    @Value("${userName}")
    private String userName;

    @Value("${password}")
    private String password;


    //Run this method when application started
    @EventListener(ApplicationReadyEvent.class)
    public ResultSet getConnection()
    {

        //Connect to Database
        Connection connection = null;
        String QUERY="your sql query";
        try {
            DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
            connection = DriverManager.getConnection(url, userName, password );
        } catch (SQLException e) {
        }


        //Run your query
        Statement stmt = null;
        try {
            stmt = connection.createStatement();
        } catch (SQLException e1) {
            e1.printStackTrace();
        }
        ResultSet rs = null;
        try {
            rs = stmt.executeQuery(QUERY);
        } catch (SQLException e1) {
            e1.printStackTrace();
        }

        return rs;
    }

}

不鼓励只给出代码的回答。请点击编辑并添加一些总结您的代码如何解决问题的单词,或者解释您的答案与先前答案的区别。谢谢。 - Nick

0
  1. 定义一个Spring Bean(例如GlobalConfigurationBean)
    使用作用域:@Scope(scopeName = WebApplicationContext.SCOPE_APPLICATION)
    此Bean将负责在Bean初始化期间从数据库表中获取数据(维护配置属性)。

  2. 使用@PostConstruct注释方法。
    此方法将具有从数据库表中获取配置参数的逻辑。

  3. 此bean的范围将确保仅从数据库表中获取所需配置一次(例如使用Hibernate查询或纯本机SQL),并且可用于同一应用程序中不同上下文中的所有bean。

现在,只需在希望使用这些配置属性或参数的位置注入此bean。

或者

使用:Apache Commons DatabaseConfiguration <--
注意:它不支持缓存。但我想你不需要缓存,因为数据库配置属性应该仅在应用程序启动时加载一次。

或者

传统的旧方法:通过扩展它来定义“PropertyPlaceHolderConfigurer”的自定义实现,并将其定义为Spring Bean。
此实现应具有从包含配置属性的数据库表中获取数据的逻辑。


0

使用Spring Boot中的JDBC初始化数据库(执行schema.sql和data.sql)

注意:请按照以下步骤操作

  1. 创建示例项目pom.xml(根据您的版本进行编辑)

             <?xml version="1.0" encoding="UTF-8"?>
             <project xmlns="http://maven.apache.org/POM/4.0.0"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
                 <modelVersion>4.0.0</modelVersion>
                 <parent>
                     <groupId>org.springframework.boot</groupId>
                     <artifactId>spring-boot-starter-parent</artifactId>
                     <version>3.0.1</version>
                     <relativePath /> <!-- 从存储库查找父级 -->
                 </parent>
                 <groupId>com.example</groupId>
                 <artifactId>Init_Sql_Script</artifactId>
                 <version>0.0.1-SNAPSHOT</version>
                 <name>Init_Sql_Script</name>
                 <description>使用基本SQL脚本初始化数据库</description>
                 <properties>
                     <java.version>17</java.version>
                 </properties>
                 <dependencies>
    
                     <dependency>
                         <groupId>org.springframework.boot</groupId>
                         <artifactId>spring-boot-starter-jdbc</artifactId>
                     </dependency>
    
                     <dependency>
                         <groupId>org.springframework.boot</groupId>
                         <artifactId>spring-boot-starter-web</artifactId>
                     </dependency>
    
                     <dependency>
                         <groupId>mysql</groupId>
                         <artifactId>mysql-connector-java</artifactId>
                         <scope>runtime</scope>
                     </dependency>
    
                     <dependency>
                         <groupId>org.springframework.boot</groupId>
                         <artifactId>spring-boot-starter-test</artifactId>
                         <scope>test</scope>
                     </dependency>
                 </dependencies>
    
                 <build>
                     <plugins>
                         <plugin>
                             <groupId>org.springframework.boot</groupId>
                             <artifactId>spring-boot-maven-plugin</artifactId>
                         </plugin>
                     </plugins>
                 </build>
    
             </project>
    
  2. 应用程序属性并创建新的数据库名称,例如在您的DB中的employee

            # spring boot连接到您的DB的连接代码
            spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
            spring.datasource.url=jdbc:mysql://localhost:3306/employee
            spring.datasource.username=Hari
            spring.datasource.password=1998
    
            spring.jpa.hibernate.ddl-auto=none
    
            #--- 控制SQL数据库初始化(从schema.sql和data.sql)---
            spring. SQL.init.mode=always
    
    
            #--- 如果出现任何错误,则跳过该脚本并执行下一个脚本----
            #spring.sql.init.continue-on-error=true
    
  3. 在资源文件夹中创建两个SQL文件(schema.sql-创建表查询和data.sql-插入查询)

  4. 运行应用程序,然后检查数据库,就这样。尝试一下。

对我来说它正在工作,希望它也能为您工作。


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