JDBC-PreparedStatement
JDBC-PreparedStatement
PreparedStatement作用:预编译SQL语句并执行:预防SQL注入问题。
SQL注入:是通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法。
/**
* 演示sql注入
* @throws SQLException
*/
@Test
public void testLogin_Inject() throws SQLException {
// 1. 注册驱动
// Class.forName("com.mysql.jdbc.Driver");
// 2. 获取连接
//String url = "jdbc:mysql:///db1";
String url = "jdbc:mysql:///db2?useSSL=false"; // 禁用安全连接警告
String username = "root";
String password = "1234";
Connection conn = DriverManager.getConnection(url, username, password);
// 接收用户名和密码
String name = "dgdgdfgdf";
String pwd = "' or '1' = '1";
String sql = "SELECT * FROM tb_user WHERE username='" + name + "' and password = '" + pwd + "'";
System.out.println(sql);
// SELECT * FROM tb_user WHERE username='dgdgdfgdf' and password = '' or '1' = '1'
// 获取stmt对象
Statement stmt = conn.createStatement();
// 执行sql
ResultSet rs = stmt.executeQuery(sql);
// 判断是否登录成功
if (rs.next()) {
System.out.println("登录成功~");
} else {
System.out.println("登录失败~");
}
// 7. 释放资源
/*rs.close();
stmt.close();
conn.close();*/
}
步骤:
-
获取PreparedStatement对象
//SQL语句中的参数值,使用?占位符替代 String sql = "SELECT * FROM user WHERE username=? and password=?"; // 通过Connection对象获取,并传入对应的sql语句 PreparedStatement pstmt = conn.preparedStatement(sql);
-
设置参数值
PreparedStatement对象:setXxx(参数1, 参数2): 给?赋值 Xxx: 数据类型;如setInt(参数1, 参数2) 参数: 参数1:?的位置编号,从1开始 参数2:?的值
-
执行SQL
executeUpdate(); / executeQuery(); 不需要再传递sql
演示:
/**
* 预编译SQL的演示
*
* @throws SQLException
*/
@Test
public void testLogin() throws SQLException {
// 1. 注册驱动
// Class.forName("com.mysql.jdbc.Driver");
// 2. 获取连接
//String url = "jdbc:mysql:///db1";
String url = "jdbc:mysql:///db2?useSSL=false"; // 禁用安全连接警告
String username = "root";
String password = "1234";
Connection conn = DriverManager.getConnection(url, username, password);
// 接收用户名和密码
String name = "zhangsan";
// String pwd = "dfghkdf";
String pwd = "' or '1' = '1";
// 定义sql
String sql = "SELECT * FROM tb_user WHERE username = ? and password = ?";
// 获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
// 设置?的值
pstmt.setString(1, name);
pstmt.setString(2, pwd);
// 防止注入前的sql语句为:
// SELECT * FROM tb_user WHERE username = 'zhangsan' AND password = '' or '1' = '1''
//最终的sql语句被转义
// SELECT * FROM tb_user WHERE username = 'zhangsan' AND password = '\' or \'1\' = \'1'
// 执行sql
ResultSet rs = pstmt.executeQuery();
// 判断是否登录成功
if (rs.next()) {
System.out.println("登录成功~");
} else {
System.out.println("登录失败~");
}
// 7. 释放资源
/*rs.close();
stmt.close();
conn.close();*/
}
PreparedStatement原理
- PreparedStatement好处:
- 预编译SQL,性能更高
- 防止SQL注入:将敏感字符进行转义
- PreparedStatement预编译功能开启:useServerPrepStmts=true
- 配置MySQL执行日志(重启MySQL服务器后生效)
log-output=FILE
general-log=1
general_log_file="D:\mysql.log"
slow-query_log_file="D:\mysql_slow.log"
long_query_time=2
- PreparedStatement原理:
- 在获取PreparedStatement对象时,将sql语句发送给mysql服务器进行检查,编译(这些步骤很耗时)
- 执行时就不用再进行这些步骤了,速度很快
- 如果sql模板一样,则只需要进行一次检查、编译