簡體   English   中英

如何在 Java 中執行 SQL 腳本文件?

[英]How to Execute SQL Script File in Java?

我想在 Java 中執行一個 SQL 腳本文件,而不是將整個文件內容讀入一個大查詢並執行它。

有沒有其他標准方法?

只要您不介意依賴 Ant,就可以從 Java 執行 SQL 腳本,而無需自己閱讀它們。 在我看來,這種依賴在你的情況下是非常合理的。 這是示例代碼,其中 SQLExec 類位於 ant.jar 中:

private void executeSql(String sqlFilePath) {
    final class SqlExecuter extends SQLExec {
        public SqlExecuter() {
            Project project = new Project();
            project.init();
            setProject(project);
            setTaskType("sql");
            setTaskName("sql");
        }
    }

    SqlExecuter executer = new SqlExecuter();
    executer.setSrc(new File(sqlFilePath));
    executer.setDriver(args.getDriver());
    executer.setPassword(args.getPwd());
    executer.setUserid(args.getUser());
    executer.setUrl(args.getUrl());
    executer.execute();
}

沒有便攜式方法可以做到這一點。 您可以將本機客戶端作為外部程序執行來執行此操作:

import java.io.*;
public class CmdExec {

  public static void main(String argv[]) {
    try {
      String line;
      Process p = Runtime.getRuntime().exec
        ("psql -U username -d dbname -h serverhost -f scripfile.sql");
      BufferedReader input =
        new BufferedReader
          (new InputStreamReader(p.getInputStream()));
      while ((line = input.readLine()) != null) {
        System.out.println(line);
      }
      input.close();
    }
    catch (Exception err) {
      err.printStackTrace();
    }
  }
}
  • 代碼示例從這里提取並修改為回答問題,假設用戶想要執行 PostgreSQL 腳本文件。

Flyway 庫對此非常有用:

    Flyway flyway = new Flyway();
    flyway.setDataSource(dbConfig.getUrl(), dbConfig.getUsername(), dbConfig.getPassword());
    flyway.setLocations("classpath:db/scripts");
    flyway.clean();
    flyway.migrate();

這會掃描腳本的位置並按順序運行它們。 腳本可以使用 V01__name.sql 進行版本控制,因此如果只調用 migrate,那么只會運行那些尚未運行的腳本。 使用名為“schema_version”的表來跟蹤事物。 但也可以做其他事情,請參閱文檔: flyway

clean 調用不是必需的,但對於從干凈的數據庫開始很有用。 另外,請注意位置(默認為“classpath:db/migration”),':' 后面沒有空格,這讓我很困惑。

不,您必須讀取文件,將其拆分為單獨的查詢,然后單獨執行(或使用 JDBC 的批處理 API)。

原因之一是每個數據庫都定義了自己的分隔 SQL 語句的方式(有些使用; ,有些使用/ ,有些允許兩者甚至定義自己的分隔符)。

您不能使用 JDBC,因為它不支持 . 解決方法是包括 iBatis iBATIS 是一個持久性框架,並調用Scriptrunner構造函數,如iBatis文檔中所示。

包含像 ibatis 這樣的重量級持久性框架以運行簡單的 sql 腳本並不好,您可以使用命令行以任何方式執行此操作

$ mysql -u root -p db_name < test.sql

由於 JDBC 不支持此選項,因此解決此問題的最佳方法是通過 Java 程序執行命令行。 Bellow 是 postgresql 的一個例子:

private void executeSqlFile() {
     try {
         Runtime rt = Runtime.getRuntime();
         String executeSqlCommand = "psql -U (user) -h (domain) -f (script_name) (dbName)";
         Process pr = rt.exec();
         int exitVal = pr.waitFor();
         System.out.println("Exited with error code " + exitVal);
      } catch (Exception e) {
        System.out.println(e.toString());
      }
}

我發現也是可移植的最簡單的外部工具是 jisql - https://www.xigole.com/software/jisql/jisql.jsp 你會運行它:

java -classpath lib/jisql.jar:\
          lib/jopt-simple-3.2.jar:\
          lib/javacsv.jar:\
           /home/scott/postgresql/postgresql-8.4-701.jdbc4.jar 
    com.xigole.util.sql.Jisql -user scott -password blah     \
    -driver postgresql                                       \
    -cstring jdbc:postgresql://localhost:5432/scott -c \;    \
    -query "select * from test;"

JDBC 不支持此選項(盡管特定的 DB 驅動程序可能會提供此選項)。 無論如何,將所有文件內容加載到內存中應該沒有問題。

試試這個代碼:

String strProc =
         "DECLARE \n" +
         "   sys_date DATE;"+
         "" +
         "BEGIN\n" +
         "" +
         "   SELECT SYSDATE INTO sys_date FROM dual;\n" +
         "" +
         "END;\n";

try{
    DriverManager.registerDriver ( new oracle.jdbc.driver.OracleDriver () );
    Connection connection = DriverManager.getConnection ("jdbc:oracle:thin:@your_db_IP:1521:your_db_SID","user","password");  
    PreparedStatement psProcToexecute = connection.prepareStatement(strProc);
    psProcToexecute.execute();
}catch (Exception e) {
    System.out.println(e.toString());  
}

如果您使用Spring,您可以使用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

Apache iBatis 解決方案就像一個魅力。

我使用的腳本示例正是我從 MySql 工作台運行的腳本。

這里有一篇帶有示例的文章: https : //www.tutorialspoint.com/how-to-run-sql-script-using-jdbc# :~: text=You%20can%20execute%20.,to%20pass% 20a%20connection%20object.&text=注冊%20the%20MySQL%20JDBC%20Driver,method%20of%20the%20DriverManager%20class

這就是我所做的:

pom.xml 依賴

<!-- IBATIS SQL Script runner from Apache (https://mvnrepository.com/artifact/org.apache.ibatis/ibatis-core) -->
<dependency>
    <groupId>org.apache.ibatis</groupId>
    <artifactId>ibatis-core</artifactId>
    <version>3.0</version>
</dependency>

執行腳本的代碼:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.Reader;
import java.sql.Connection;   
import org.apache.ibatis.jdbc.ScriptRunner;   
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class SqlScriptExecutor {

    public static void executeSqlScript(File file, Connection conn) throws Exception {
        Reader reader = new BufferedReader(new FileReader(file));
        log.info("Running script from file: " + file.getCanonicalPath());
        ScriptRunner sr = new ScriptRunner(conn);
        sr.setAutoCommit(true);
        sr.setStopOnError(true);
        sr.runScript(reader);
        log.info("Done.");
    }
    
}

對於我的簡單項目,用戶應該能夠選擇執行的 SQL 文件。 由於我對其他答案不滿意,並且無論如何我都在使用 Flyway,因此我仔細查看了 Flyway 代碼。 DefaultSqlScriptExecutor正在執行實際執行,所以我試圖弄清楚如何創建DefaultSqlScriptExecutor的實例。

基本上,以下代碼段加載一個String將其拆分為單個語句並一一執行。 Flyway 還提供了StringResource之外的其他LoadableResource例如FileSystemResource 但我沒有仔細觀察它們。

由於DefaultSqlScriptExecutor和其他類沒有被 Flyway 正式記錄,請小心使用代碼片段。

public static void execSqlQueries(String sqlQueries, Configuration flyWayConf) throws SQLException {
  // create dependencies FlyWay needs to execute the SQL queries
  JdbcConnectionFactory jdbcConnectionFactory = new JdbcConnectionFactory(flyWayConf.getDataSource(),
      flyWayConf.getConnectRetries(),
      null);
  DatabaseType databaseType = jdbcConnectionFactory.getDatabaseType();
  ParsingContext parsingContext = new ParsingContext();
  SqlScriptFactory sqlScriptFactory = databaseType.createSqlScriptFactory(flyWayConf, parsingContext);
  Connection conn = flyWayConf.getDataSource().getConnection();
  JdbcTemplate jdbcTemp = new JdbcTemplate(conn);
  ResourceProvider resProv = flyWayConf.getResourceProvider();
  DefaultSqlScriptExecutor scriptExec = new DefaultSqlScriptExecutor(jdbcTemp, null, false, false, false, null);
  
  // Prepare and execute the actual queries
  StringResource sqlRes = new StringResource(sqlQueries);
  SqlScript sqlScript = sqlScriptFactory.createSqlScript(sqlRes, true, resProv);
  scriptExec.execute(sqlScript);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM