Java SQL 语句关闭
Posted
技术标签:
【中文标题】Java SQL 语句关闭【英文标题】:Java SQL Statement closing 【发布时间】:2020-04-29 16:24:56 【问题描述】:我有一个简单的 Java 程序,它监听命令然后执行 SQL 查询。程序结构如下:
启动时连接到数据库 运行 SQL 查询以创建 TABLE IF NOT EXIST (First Statement
)
监听命令foo
并运行foo(cmd)
方法
在此方法中执行 SQL 查询 (Second Statement
)
这可以重复多次
程序终止时关闭连接
我的问题是如何处理Statements
。我应该为每个查询create->execute->close
吗?
或者我应该创建一个Statement
并多次使用它(statement.execute();
)直到我停止应用程序?
我问是因为我的 mysql 服务器有时非常滞后,我认为这是因为我有太多未关闭的语句或池连接。
我有时也会出错:
java.sql.SQLException: 语句关闭后不允许任何操作。
【问题讨论】:
您应该为每个查询创建->执行->关闭。否则你会泄露资源。你应该使用连接池。如果您想要更好的性能,请使用PreparedStatement
,您可能需要调整获取大小。这不是一个可以很好地涵盖 SO 的主题。关于优化使用 sql 的应用程序的书籍有很多。
我不需要优化 :) 我只需要确认,我应该打开->执行->关闭。我不确定语句不应该处理多个查询。
【参考方案1】:
你应该很少使用Statement
;你几乎总是想要PreparedStatement
。使用Statement
意味着您不能将任何用户输入放入语句中。如果你尝试,即:statement.executeQuery("SELECT * FROM users WHERE username = '" + userInput + "'");
,你刚刚写了一个安全漏洞。如果用户作为输入发送:"foo'; DROP TABLE users; EXECUTE SHELL 'rm -rf /'; --"?
- 唯一的出路是转义它,PreparedStatement
是如何做到这一点的。
连接是资源;他们必须关闭。语句(甚至是preparedstatements)也是如此,结果集也是如此。每个都需要被视为一种资源。
要使用资源,您可以编写如下代码:
try (Connection con = DriverManager.getConnection(...))
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM users WHERE username = ?"))
ps.setString(1, username);
try (ResultSet rs = ps.executeQuery())
while (rs.next())
// handle a row worth of results here
这种构造确保无论发生什么(您返回、中断、抛出异常 - 无关紧要),一旦代码移出大括号,资源就会被正确地处理掉。不这样做意味着数据库引擎会随着时间的推移变得越来越迟钝,最终您的应用程序会崩溃,因为数据库停止为您提供更多连接以让您闲置。
【讨论】:
资源究竟什么时候“关闭”?据我了解,我不需要在 conn/statement 上明确调用.close()
您需要显式调用 close,通常在 finally
子句中。不过,正如在这个答案中一样,“使用资源尝试”会自动为您执行此操作。
@Baterka 资源在代码从此处的 try 语句的大括号中流出时关闭。没关系。所以,如果你在 try (Connection con = ...) /* code here / return 中间返回; / 这里有更多代码 */ – 在它实际返回之前,资源首先被关闭。如果代码通过异常退出块,或者仅仅因为它到达末尾,也是如此。您无需自己致电 close,它会为您处理好。以上是关于Java SQL 语句关闭的主要内容,如果未能解决你的问题,请参考以下文章
java.sql.SQLException: SQL 语句在 org.hsqldb.jdbc.JDBCUtil.sqlException 处关闭