昨天Stack上的多个人建议使用try-with-resources。我正在为我的所有数据库操作执行此操作。今天我想将Statement更改为PreparedStatement以使查询更安全。但是,当我尝试在try-with-resources中使用预准备语句时,我不断收到“标识符预期”或“;”等错误或')'。
我做错了什么?或者这不可能吗?这是我的代码:
try (Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPASS);
PreparedStatement stmt = conn.prepareStatement("SELECT id FROM users WHERE id = ? LIMIT 1");
stmt.setInt(1, user);
ResultSet rs = stmt.executeQuery()) {
// if no record found
if(!rs.isBeforeFirst()) {
return false;
}
// if record found
else {
return true;
}
} catch (SQLException e) {
// log error but dont do anything, maybe later
String error = "SQLException: " + e.getMessage() + "\nSQLState: " + e.getSQLState() + "\nVendorError: " + e.getErrorCode();
return false;
}
答案 0 :(得分:8)
try-with-resource语句用于声明(Autoclosable
)资源。 Connection
,PreparedStatement
和ResultSet
为Autoclosable
,这样就可以了。
但stmt.setInt(1, user)
不是资源,而是简单的陈述。在try-with-resource语句中不能有简单的语句(不是资源声明)!
解决方案:创建多个try-with-resource语句!
try (Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPASS)) {
executeStatement(conn);
} catch (SQLException e) {
// log error but dont do anything, maybe later
String error = "SQLException: " + e.getMessage() + "\nSQLState: " + e.getSQLState() + "\nVendorError: " + e.getErrorCode();
return false;
}
private void executeStatement(Connection con) throws SQLException {
try (PreparedStatement stmt = conn.prepareStatement("SELECT id FROM users WHERE id=? LIMIT 1")) {
stmt.setInt(1, user);
try (ResultSet rs = stmt.executeQuery()) {
// process result
}
}
}
(请注意,从技术上讲,不需要像我一样将SQL语句的执行放入单独的方法中。如果打开连接和创建PreparedStatement
两者都在同一个尝试中,它也可以工作-with-resource statement。我认为将连接管理内容与其余代码分开是一种很好的做法。
答案 1 :(得分:1)
试试这段代码:
try (Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPASS)) {
PreparedStatement stmt = conn.prepareStatement("SELECT id FROM users WHERE id = ? LIMIT 1");
stmt.setInt(1, user);
ResultSet rs = pstmt.executeQuery())
// if no record found
if(!rs.isBeforeFirst()) {
return false;
}
// if record found
else {
return true;
}
} catch (SQLException e) {
// log error but dont do anything, maybe later
String error = "SQLException: " + e.getMessage() + "\nSQLState: " + e.getSQLState() + "\nVendorError: " + e.getErrorCode();
return false;
}
请注意,此处资源是您的Connection,您必须在try块中使用它()
答案 2 :(得分:1)
移动
stmt.setInt(1, user);
ResultSet rs = stmt.executeQuery()
...在try{ /*HERE*/ }
这是因为stmt
是要使用的资源try (/*HERE*/) {}
try{ /*HERE*/ }
<强>尝试与 - 资源强>
try (/*Create resources in here such as conn and stmt*/)
{
//Use the resources created above such as stmt
}
关键是在资源创建块implements AutoClosable
中创建的所有内容以及退出try
块时,都会调用close()
。
在您的代码中,stmt.setInt(1, user);
不是AutoCloseable
资源,因此存在问题。