如何使用 JDBC 执行 .sql 脚本文件 [重复]
Posted
技术标签:
【中文标题】如何使用 JDBC 执行 .sql 脚本文件 [重复]【英文标题】:How to execute .sql script file using JDBC [duplicate] 【发布时间】:2010-12-02 15:00:10 【问题描述】:可能重复:Running a .sql script using mysql with JDBC
我有一个包含 40-50 个 SQL 语句的 SQL 脚本文件。是否可以使用 JDBC 运行此脚本文件?
【问题讨论】:
【参考方案1】:此链接可能会对您有所帮助:http://pastebin.com/f10584951。
粘贴在下面以供后代使用:
/*
* Slightly modified version of the com.ibatis.common.jdbc.ScriptRunner class
* from the iBATIS Apache project. Only removed dependency on Resource class
* and a constructor
*/
/*
* Copyright 2004 Clinton Begin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.sql.*;
/**
* Tool to run database scripts
*/
public class ScriptRunner
private static final String DEFAULT_DELIMITER = ";";
private Connection connection;
private boolean stopOnError;
private boolean autoCommit;
private PrintWriter logWriter = new PrintWriter(System.out);
private PrintWriter errorLogWriter = new PrintWriter(System.err);
private String delimiter = DEFAULT_DELIMITER;
private boolean fullLineDelimiter = false;
/**
* Default constructor
*/
public ScriptRunner(Connection connection, boolean autoCommit,
boolean stopOnError)
this.connection = connection;
this.autoCommit = autoCommit;
this.stopOnError = stopOnError;
public void setDelimiter(String delimiter, boolean fullLineDelimiter)
this.delimiter = delimiter;
this.fullLineDelimiter = fullLineDelimiter;
/**
* Setter for logWriter property
*
* @param logWriter
* - the new value of the logWriter property
*/
public void setLogWriter(PrintWriter logWriter)
this.logWriter = logWriter;
/**
* Setter for errorLogWriter property
*
* @param errorLogWriter
* - the new value of the errorLogWriter property
*/
public void setErrorLogWriter(PrintWriter errorLogWriter)
this.errorLogWriter = errorLogWriter;
/**
* Runs an SQL script (read in using the Reader parameter)
*
* @param reader
* - the source of the script
*/
public void runScript(Reader reader) throws IOException, SQLException
try
boolean originalAutoCommit = connection.getAutoCommit();
try
if (originalAutoCommit != this.autoCommit)
connection.setAutoCommit(this.autoCommit);
runScript(connection, reader);
finally
connection.setAutoCommit(originalAutoCommit);
catch (IOException e)
throw e;
catch (SQLException e)
throw e;
catch (Exception e)
throw new RuntimeException("Error running script. Cause: " + e, e);
/**
* Runs an SQL script (read in using the Reader parameter) using the
* connection passed in
*
* @param conn
* - the connection to use for the script
* @param reader
* - the source of the script
* @throws SQLException
* if any SQL errors occur
* @throws IOException
* if there is an error reading from the Reader
*/
private void runScript(Connection conn, Reader reader) throws IOException,
SQLException
StringBuffer command = null;
try
LineNumberReader lineReader = new LineNumberReader(reader);
String line = null;
while ((line = lineReader.readLine()) != null)
if (command == null)
command = new StringBuffer();
String trimmedLine = line.trim();
if (trimmedLine.startsWith("--"))
println(trimmedLine);
else if (trimmedLine.length() < 1
|| trimmedLine.startsWith("//"))
// Do nothing
else if (trimmedLine.length() < 1
|| trimmedLine.startsWith("--"))
// Do nothing
else if (!fullLineDelimiter
&& trimmedLine.endsWith(getDelimiter())
|| fullLineDelimiter
&& trimmedLine.equals(getDelimiter()))
command.append(line.substring(0, line
.lastIndexOf(getDelimiter())));
command.append(" ");
Statement statement = conn.createStatement();
println(command);
boolean hasResults = false;
if (stopOnError)
hasResults = statement.execute(command.toString());
else
try
statement.execute(command.toString());
catch (SQLException e)
e.fillInStackTrace();
printlnError("Error executing: " + command);
printlnError(e);
if (autoCommit && !conn.getAutoCommit())
conn.commit();
ResultSet rs = statement.getResultSet();
if (hasResults && rs != null)
ResultSetMetaData md = rs.getMetaData();
int cols = md.getColumnCount();
for (int i = 0; i < cols; i++)
String name = md.getColumnLabel(i);
print(name + "\t");
println("");
while (rs.next())
for (int i = 0; i < cols; i++)
String value = rs.getString(i);
print(value + "\t");
println("");
command = null;
try
statement.close();
catch (Exception e)
// Ignore to workaround a bug in Jakarta DBCP
Thread.yield();
else
command.append(line);
command.append(" ");
if (!autoCommit)
conn.commit();
catch (SQLException e)
e.fillInStackTrace();
printlnError("Error executing: " + command);
printlnError(e);
throw e;
catch (IOException e)
e.fillInStackTrace();
printlnError("Error executing: " + command);
printlnError(e);
throw e;
finally
conn.rollback();
flush();
private String getDelimiter()
return delimiter;
private void print(Object o)
if (logWriter != null)
System.out.print(o);
private void println(Object o)
if (logWriter != null)
logWriter.println(o);
private void printlnError(Object o)
if (errorLogWriter != null)
errorLogWriter.println(o);
private void flush()
if (logWriter != null)
logWriter.flush();
if (errorLogWriter != null)
errorLogWriter.flush();
【讨论】:
这个解决方案只对基本的东西有用。例如,如果您只有一组简单的 select/update/insert 语句等。但是如果您尝试以这种方式创建存储过程......它会失败。 根据 Shafi 的说法,他有“40-50 条 sql 语句”,这意味着他的 SQL 脚本中没有 SP。 :) 因为我已经在使用 Mybatis,所以能把事情做起来真是太好了。 这不是有点破吗?ResultSet
使用从 1 开始的列索引,但这是使用从 0 开始的。
它在这一行给了我一个错误 - command.append(line.substring(0, line .lastIndexOf(getDelimiter())));它是一个编译时间错误。错误是这样的 - java.lang.CharSequence 类型无法解析。它是从所需的 .class 文件中间接引用的【参考方案2】:
我用这段代码导入mysqldump创建的sql语句:
public static void importSQL(Connection conn, InputStream in) throws SQLException
Scanner s = new Scanner(in);
s.useDelimiter("(;(\r)?\n)|(--\n)");
Statement st = null;
try
st = conn.createStatement();
while (s.hasNext())
String line = s.next();
if (line.startsWith("/*!") && line.endsWith("*/"))
int i = line.indexOf(' ');
line = line.substring(i + 1, line.length() - " */".length());
if (line.trim().length() > 0)
st.execute(line);
finally
if (st != null) st.close();
【讨论】:
不需要为每一行创建一个语句(conn.createStatement())吗? 我用s.useDelimiter("(;(\r)?\n)|((\r)?\n)?(--)?.*(--(\r)?\n)");
【参考方案3】:
另一个选项,这不支持 cmets,对于 Apache Derby 的 AmaterasERD DDL 导出非常有用:
public void executeSqlScript(Connection conn, File inputFile)
// Delimiter
String delimiter = ";";
// Create scanner
Scanner scanner;
try
scanner = new Scanner(inputFile).useDelimiter(delimiter);
catch (FileNotFoundException e1)
e1.printStackTrace();
return;
// Loop through the SQL file statements
Statement currentStatement = null;
while(scanner.hasNext())
// Get statement
String rawStatement = scanner.next() + delimiter;
try
// Execute statement
currentStatement = conn.createStatement();
currentStatement.execute(rawStatement);
catch (SQLException e)
e.printStackTrace();
finally
// Release resources
if (currentStatement != null)
try
currentStatement.close();
catch (SQLException e)
e.printStackTrace();
currentStatement = null;
scanner.close();
【讨论】:
【参考方案4】:只需阅读它,然后使用其中包含完整 sql 文件的preparedstatement。
(如果我没记错的话)
添加:您还可以在";"
上读取和拆分,然后循环执行它们。
不要忘记 cmets 并再次添加 ";"
【讨论】:
它没有用。为“;”引发错误它出现在每个 sql 语句的末尾。 然后删除分号 - 准备好的语句可能不带分隔符。 为分裂小费点赞! 如果您的字符串之一包含 ; ?【参考方案5】:您应该能够将 SQL 文件解析为语句。并且一次运行一个语句。如果您知道您的文件包含简单的插入/更新/删除语句,则可以使用分号作为语句分隔符。通常情况下,您需要创建特定的 SQL 方言解析器。
【讨论】:
【参考方案6】:我在尝试执行创建 SQL 数据库的 SQL 脚本时遇到了同样的问题。到处搜索,我发现了一个最初由 Clinton Begin 编写的 Java 类,它支持 cmets(参见 http://pastebin.com/P14HsYAG)。我稍微修改了文件以适应触发器,其中必须将默认 DELIMITER 更改为不同的东西。我用过那个版本的 ScriptRunner(见http://pastebin.com/sb4bMbVv)。由于(开源和免费)SQLScriptRunner 类是绝对必要的实用程序,因此最好从开发人员那里获得更多意见,希望我们很快就会有一个更稳定的版本。
【讨论】:
【参考方案7】:您可以使用BufferedReader
每行读取脚本行并将每一行附加到StringBuilder
,以便脚本变成一个大字符串。
然后您可以使用 JDBC 创建一个Statement
对象并调用statement.execute(stringBuilder.toString())
。
【讨论】:
.execute 如果字符串多于一行,则抛出错误。您需要逐行执行,如先前的答案所示以上是关于如何使用 JDBC 执行 .sql 脚本文件 [重复]的主要内容,如果未能解决你的问题,请参考以下文章
去掉utf-8的Bom头:使用java以及jdbc不使用第三方库执行sql文件脚本