企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
执行SQL语句一共就三个接口Statement、PreparedStatement、CallableStatement。![](https://img.kancloud.cn/5a/38/5a388813a32d6ddc2ef448ff2e7cfd22_1119x134.jpg) 由于Statement不支持参数化命令,可能会导致SQL注入问题,即有人可以乱改动一部分代码,导致你的数据库发生意料之外的事。而使用PreparedSatement和CallableStatement要安全。 <br/> **1. Statement查询** Statement执行SQL语句不支持参数化命令,是纯字符串拼接,会导致SQL注入,及不安全。 ```java public class SafeTest { private final String username = "lisi"; //像这样的字符串叫对等条件,也可以是"' or '2'='2"; private final String password = "' or '1'='1"; @Test public void testStatement() throws SQLException { String sql = "select username, password from admin where username='" + username + "' and password='" + password + "'"; System.out.println(sql); //select username, password from admin where username='lisi' and password='' or '1'='1' Connection conn = ConnUtils.getConnection3(); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql); //结果:账号与密码根本就不对,依然查出了所有数据 while (rs.next()) { System.out.println(rs.getString("username") + "\t" + rs.getString("password")); } //zhangsan zhangsan123 //lisi lisi123 rs.close(); stmt.close(); conn.close(); } } ``` **2. PreparedStatement查询** PreparedStatement接口支持参数化命令,执行SQL语句安全。 ```java public class SafeTest { private final String username = "lisi"; //像这样的字符串叫对等条件,也可以是"' or '2'='2"; private final String password = "' or '1'='1"; @Test public void testPreparedStatement() throws SQLException { String sql = "select username, password from admin where username=? and password=?"; Connection conn = ConnUtils.getConnection3(); //预编译 PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, username); pstmt.setString(2, password); ResultSet rs = pstmt.executeQuery(); //结果:账号与密码不满足条件,所以一个都查不到,安全。 while (rs.next()) { System.out.println(rs.getString("username") + "\t" + rs.getString("password")); } rs.close(); pstmt.close(); conn.close(); } } ``` **3. CallableStatement查询** CallableStatement接口用于执行对数据库存储过程的调用,该接口执行SQL语句更高效和安全。 <br/> 使用该接口的步骤如下: (1)封装存储过程。 ```sql DELIMITER $$ CREATE /*[DEFINER = { user | CURRENT_USER }]*/ PROCEDURE `jdbc_db`.`login`(IN user_ VARCHAR(50), IN pass_ VARCHAR(50)) # jdbc_db是数据库名、login是存储过程名、in为输入 # user_、pass_ 的数据类型必须与数据库中的admin表一致 # user_、pass_ 绝对不能与 admin表 上的列名一致,否则依旧是不安全的 /*LANGUAGE SQL | [NOT] DETERMINISTIC | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA } | SQL SECURITY { DEFINER | INVOKER } | COMMENT 'string'*/ BEGIN SELECT username,password FROM admin WHERE username=user_ AND `password`=pass_; END$$ DELIMITER ; ``` (2)通过CallableStatement接口调用存储过程。 ```java public class SafeTest { private final String username = "lisi"; //像这样的字符串叫对等条件,也可以是"' or '2'='2"; private final String password = "' or '1'='1"; @Test public void testCallableStatement() throws SQLException { //调用存储过程 String sql = "{call login(?,?)}"; Connection conn = ConnUtils.getConnection3(); // 预编译 CallableStatement cstmt = conn.prepareCall(sql); cstmt.setString(1, username); cstmt.setString(2, password); ResultSet rs = cstmt.executeQuery(); //结果:账号与密码不满足条件,所以一个都查不到,安全。 while (rs.next()) { System.out.println(rs.getString("username") + "\t" + rs.getString("password")); } rs.close(); cstmt.close(); conn.close(); } } ```