使用带有 JDBC 的 MySQL 运行 .sql 脚本
Posted
技术标签:
【中文标题】使用带有 JDBC 的 MySQL 运行 .sql 脚本【英文标题】:Running a .sql script using MySQL with JDBC 【发布时间】:2010-11-05 20:43:17 【问题描述】:我开始使用带有 JDBC 的 mysql。
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql:///x", "x", "x");
stmt = conn.createStatement();
stmt.execute( "CREATE TABLE amigos" +
"("+
"id int AUTO_INCREMENT not null,"+
"nombre char(20) not null,"+
"primary key(id)" +
")");
我要创建 3-4 个表,这看起来不太好。
有没有办法从 MySQL JDBC 运行 .sql 脚本?
【问题讨论】:
您需要编写 java 代码来运行这些创建表语句的任何特殊原因?它们在某种程度上是动态的吗? 因为他想用 Java xD 做所有的事情 【参考方案1】:你能用这个吗:
public static void executeSQL(File f, Connection c) throws Exception
BufferedReader br = new BufferedReader(new FileReader(f));
String sql = "", line;
while ((line = br.readLine()) != null) sql += (line+"\n");
c.prepareCall(sql).execute(sql);
此函数获取 SQL 文件和 DB 连接。 然后它使用 java.io 中的 BufferedReader 逐行读取文件。 最后,执行读取语句。
Java 8+ 版本:
public static void executeSQL(Path p, Connection c) throws Exception
List<String> lines = Files.readAllLines(p);
String s = String.join("\n", lines.toArray(new String[0]));
c.prepareCall(s).execute(s);
【讨论】:
虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高答案的长期价值。请阅读此how-to-answer 以提供高质量的答案。【参考方案2】:另一个有趣的选择是使用Jisql 来运行脚本。由于源代码可用,应该可以将其嵌入到应用程序中。
编辑:仔细看了一下;将其嵌入到其他东西中需要对其源代码进行一些修改。
【讨论】:
【参考方案3】:好的。你可以在你的项目中使用这个类(由于文件长度而发布在 pastebin 上)。但请记住保留 apache 许可证信息。
JDBC ScriptRunner
它是对 iBatis ScriptRunner 的剽窃,移除了依赖项。
你可以这样使用它
Connection con = ....
ScriptRunner runner = new ScriptRunner(con, [booleanAutoCommit], [booleanStopOnerror]);
runner.runScript(new BufferedReader(new FileReader("test.sql")));
就是这样!
【讨论】:
非常少的一类。我必须补充一点,第 130 行可能会引起头痛。我将其替换为“String trimmedLine = line.trim().replaceAll(";$", Matcher.quoteReplacement("; \\"));"因为你可能会得到***.com/questions/3499483/… 这可以用于返回ResultSet
还是仅适用于更新语句?我尝试使用它,但不知道如何让它返回ResultSet
。我会选择Spring
,但使用一个类比使用整个库更容易。
对链接到脚本要小心一点——如果你的脚本有一个像select 1; -- do nothing
这样的代码“注释”,那么脚本不会执行它,而是把它当作更长的前半部分命令 [与新命令连接] 其他副作用——如果这是文件中的最后一件事,它根本不会运行它]。如果你只是坚持使用单行 sql cmets 没关系
这个类永远无法处理 PROCEDURE
我冒昧地复制代码,更新它以添加对存储过程分隔符的支持,将其上传到 GitHub,并更新@jitter 答案中的链接。【参考方案4】:
对于用';'分割的简单sql脚本你可以使用这个简单的功能。 它删除 cmets 并逐个运行语句
static void executeScript(Connection conn, InputStream in)
throws SQLException
Scanner s = new Scanner(in);
s.useDelimiter("/\\*[\\s\\S]*?\\*/|--[^\\r\\n]*|;");
Statement st = null;
try
st = conn.createStatement();
while (s.hasNext())
String line = s.next().trim();
if (!line.isEmpty())
st.execute(line);
finally
if (st != null)
st.close();
【讨论】:
您假设 cmets 不能出现在单个语句中。在 CREATE TABLE 中这很常见。 我会说更多。它不支持复杂查询,但您可以将分隔符更改为其他内容,例如 ';[\s\r\n]*\\'。并根据需要使用 cmets。 抱歉,这个效果更好***.com/questions/1497569/… Atais,很高兴看到你的尝试......我的代码只是一个例子,你可以使用它:)【参考方案5】:我对此做了很多研究,发现了一个很好的util from spring。我认为使用SimpleJdbcTestUtils.executeSqlScript(...)
实际上是最好的解决方案,因为它得到了更多的维护和测试。
编辑:SimpleJdbcTestUtils
已弃用。你应该使用JdbcTestUtils
。更新了链接。
【讨论】:
感谢@Amir Raminfar,您的回答帮助了我。无论如何,作为更新,spring 弃用了SimpleJdbcTestUtil
,并建议将来使用JdbcTestUtils
。
这是最好的答案,Spring 框架团队很活跃。
从 Spring 4.0.3 开始。 JdbcTestUtils.executeSqlScript()
方法现已弃用。应该改用ScriptUtils.executeSqlScript(...)
。
请注意,无论是否积极开发,这些实用程序类在设计时都考虑到了测试,并且对于大多数情况来说是不够的;例如,由于分隔符问题,它们不允许您创建存储过程; joe776's answer 可能是更好的选择,这取决于您的需要,【参考方案6】:
Maven SQL Plugin使用这个插件通过一个文件或者文件列表执行SQL语句
-
sqlCommand
src 文件
3.文件集配置
【讨论】:
【参考方案7】:Spring Framework 的ResourceDatabasePopulator
可能会有所帮助。正如您所说,您正在使用 MySQL 和 JDBC,假设您已准备好由 MySQL 支持的 DataSource
实例。此外,假设您的 MySQL 脚本文件是类路径可定位的。假设您正在使用 WAR 布局,并且脚本文件位于目录 src/main/webapp/resources/mysql-scripts/...
或 src/test/resources/mysql-scripts/...
中。然后你可以使用ResourceDatabasePopulator
来执行这样的SQL脚本:
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import javax.sql.DataSource;
DataSource dataSource = getYourMySQLDriverBackedDataSource();
ResourceDatabasePopulator rdp = new ResourceDatabasePopulator();
rdp.addScript(new ClassPathResource(
"mysql-scripts/firstScript.sql"));
rdp.addScript(new ClassPathResource(
"mysql-scripts/secondScript.sql"));
try
Connection connection = dataSource.getConnection();
rdp.populate(connection); // this starts the script execution, in the order as added
catch (SQLException e)
e.printStackTrace();
【讨论】:
到目前为止最好的答案在这里。我厌倦了看到告诉您从命令行运行 MySQL 转储导入的答案。在数据库位于不同服务器上的自动化环境中效果不佳。 @Zoidbergmysql
命令行客户端和mysqldump
在网络上运行良好,可以在自动化脚本中使用。将数据库放在不同的服务器上应该没有问题。
@Asaph 你是对的。我实际上尝试了上述解决方案,发现性能真的很慢。我可以很好地使用命令行参数,所以我上面的评论实际上是不正确的。【参考方案8】:
@Pantelis Sopasakis
GitHub上略有修改的版本:https://gist.github.com/831762/
在那里更容易跟踪修改。
【讨论】:
在修复了这个要点的评论中的错误之后,这似乎工作到目前为止!【参考方案9】:关于 SQL 脚本运行器(我也在使用),我注意到以下代码:
for (int i = 0; i < cols; i++)
String value = rs.getString(i);
print(value + "\t");
但是,在方法 getString(int) 的 API 文档中提到了 indexes start with 1,所以应该变成:
for (int i = 1; i <= cols; i++)
String value = rs.getString(i);
print(value + "\t");
其次,ScriptRunner 的这个实现不支持 SQL 脚本中的 DELIMITER 语句,如果您需要编译 TRIGGERS 或 PROCEDURES,这些语句很重要。所以我创建了这个修改版的 ScriptRunner:http://pastebin.com/ZrUcDjSx,希望对你有用。
【讨论】:
这很有帮助。非常感谢。【参考方案10】:对于 Oracle PL/SQL,Oracle JDBC 驱动程序确实支持执行整个 SQL 脚本,包括存储过程和匿名块(PL/SQL 特定符号),请参阅
Can the JDBC Drivers access PL/SQL Stored Procedures?
Oracle JDBC driver FAQ 有更多信息:
Oracle JDBC 驱动程序支持执行 PL/SQL 存储过程和 匿名块。他们都支持 SQL92 转义语法和 Oracle PL/SQL 块语法。以下 PL/SQL 调用适用于任何 Oracle JDBC 司机:
// SQL92 syntax
CallableStatement cs1 = conn.prepareCall
( "call proc (?,?)" ) ; // stored proc
CallableStatement cs2 = conn.prepareCall
( "? = call func (?,?)" ) ; // stored func
// Oracle PL/SQL block syntax
CallableStatement cs3 = conn.prepareCall
( "begin proc (?,?); end;" ) ; // stored proc
CallableStatement cs4 = conn.prepareCall
( "begin ? := func(?,?); end;" ) ; // stored func
应该可以读取文件并将内容提供给 prepareCall() 方法。
【讨论】:
问题的第一个链接已损坏。【参考方案11】:真的没有办法做到这一点。
当您决定使用此选项时,您可以通过 Runtime.exec(String[]) 运行 mysql 命令行客户端并阅读 this article
或者尝试使用来自ibatis 的 ScriptRunner (com.ibatis.common.jdbc.ScriptRunner)。但是为了运行脚本而包含整个库有点愚蠢。
【讨论】:
是的,这是真的。仅仅为了运行一个脚本而添加一个库是没有意义的:(我认为 jdbc 没有这样的东西很奇怪。【参考方案12】:将代码写入:
-
读入包含多个 SQL 语句的文件。
运行每个 SQL 语句。
【讨论】:
如果我这样做,我应该解析 .sql 文件。我期待有一个我找不到的 jdbc 功能。以上是关于使用带有 JDBC 的 MySQL 运行 .sql 脚本的主要内容,如果未能解决你的问题,请参考以下文章
ava基础MySQL存储过程 Java基础 JDBC连接MySQL数据库
Spring JDBC 在运行 SQL 脚本时无法处理 DECLARE 语句
带有 maven 的 mysql 连接器:java.lang.NoClassDefFoundError: com/mysql/jdbc/Driver