JDBC-API②(ResultSet、PreparedStatement)

网友投稿 287 2022-11-30

JDBC-API②(ResultSet、PreparedStatement)

文章目录

​​ResultSet​​

​​案例​​

​​PreparedStatement​​

​​代码模拟SQL注入问题​​​​PreparedStatement用法​​​​原理​​

ResultSet

ResultSet(结果集对象)作用:

封装了SQL查询语句的结果。

而执行了DQL语句后就会返回该对象,对应执行DQL语句的方法如下:

ResultSet executeQuery(sql):执行DQL 语句,返回 ResultSet 对象

那么我们就需要从 ​​ResultSet​​​ 对象中获取我们想要的数据。​​ResultSet​​ 对象提供了操作查询结果数据的方法,如下:

boolean next()将光标从当前位置向前移动一行判断当前行是否为有效行方法返回值说明:true : 有效航,当前行有数据false : 无效行,当前行没有数据xxx getXxx(参数):获取数据xxx : 数据类型;如: int getInt(参数) ;String getString(参数)参数(两种选一个用)int类型的参数:列的编号,从1开始String类型的参数: 列的名称

如下图为执行SQL语句后的结果

一开始光标指定于第一行前,如图所示红色箭头指向于表头行。当我们调用了 ​​next()​​​ 方法后,光标就下移到第一行数据,并且方法返回true,此时就可以通过 ​​getInt("id")​​​ 获取当前行id字段的值,也可以通过 ​​getString("name")​​​ 获取当前行name字段的值。如果想获取下一行的数据,继续调用 ​​next()​​ 方法,以此类推。

例如:我们获取下表的id,姓名,地址列

代码实现:

public class ReadJDBC { public static void main(String[] args) throws Exception { String url = "jdbc:mysql://localhost:3306/sql1?useSSL=false"; String username = "root"; String password = "********"; Connection connection = DriverManager.getConnection(url,username,password); String sql = "select * from stu"; Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(sql); while (resultSet.next()) { System.out.print(resultSet.getInt(1)); System.out.print(" " + resultSet.getString(2)); System.out.println(" " + resultSet.getString(5)); } //释放资源 resultSet.close(); statement.close(); connection.close(); }}

注意这里要多关闭一个资源,也就是返回的ResultSet的对象

案例

我们现在有一个需求:将每个人的数据封装在Account对象中,并且储存到ArrayList集合中。 代码实现:

public class ReadJDBC { public static void main(String[] args) throws Exception { String url = "jdbc:mysql://localhost:3306/sql1?useSSL=false"; String username = "root"; String password = "***********"; Connection connection = DriverManager.getConnection(url,username,password); String sql = "select * from stu"; Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(sql);// while (resultSet.next()) {// System.out.print(resultSet.getInt(1));// System.out.print(" " + resultSet.getString(2));// System.out.println(" " + resultSet.getString(5));// } ArrayList accounts = new ArrayList<>(); while (resultSet.next()) { Account account = new Account(); account.setName(resultSet.getString(2)); account.setAge(resultSet.getInt(3)); account.setAddress(resultSet.getString(5)); accounts.add(account); } //遍历这个列表 for (Account account : accounts) { System.out.print(account.getName()); System.out.print(account.getAge()); System.out.println(account.getAddress()); } //释放资源 resultSet.close(); statement.close(); connection.close(); }}class Account{ private String name; private int age; private String address; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; }}

PreparedStatement

作用:预编译SQL语句并执行:预防SQL注入问题

首先我们要知道什么是SQL注入?

代码模拟SQL注入问题

@Testpublic void testLogin() throws Exception { //2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写 String url = "jdbc:mysql:///db1?useSSL=false"; String username = "root"; String password = "1234"; Connection conn = DriverManager.getConnection(url, username, password); // 接收用户输入 用户名和密码 String name = "sjdljfld"; String pwd = "' or '1' = '1"; String sql = "select * from tb_user where username = '"+name+"' and password = '"+pwd+"'"; // 获取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();}

上面代码是将用户名和密码拼接到sql语句中,拼接后的sql语句如下

select * from tb_user where username = 'sjdljfld' and password = ''or '1' = '1'

从上面语句可以看出条件 ​​username = 'sjdljfld' and password = ''​​​ 不管是否满足,而 ​​or​​​ 后面的 ​​'1' = '1'​​ 是始终满足的,最终条件是成立的,就可以正常的进行登陆了。

PreparedStatement用法

我们将上面的代码用PreparedStatement进行改进:

@Testpublic void testPreparedStatement() throws Exception { //2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写 String url = "jdbc:mysql:///db1?useSSL=false"; String username = "root"; String password = "***********"; Connection conn = DriverManager.getConnection(url, username, password); // 接收用户输入 用户名和密码 String name = "zhangsan"; 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 ResultSet rs = pstmt.executeQuery(); // 判断登录是否成功 if(rs.next()){ System.out.println("登录成功~"); }else{ System.out.println("登录失败~"); } //7. 释放资源 rs.close(); pstmt.close(); conn.close();}

那么PreparedStatement又是如何解决的呢?它是将特殊字符进行了转义,转义的SQL如下:

select * from tb_user where username = 'sjdljfld' and password = '\'or \'1\' = \'1'

原理

PreparedStatement 好处:预编译SQL,性能更高防止SQL注入:将敏感字符进行转义

Java代码操作数据库流程如图所示:

将sql语句发送到MySQL服务器端MySQL服务端会对sql语句进行如下操作

① 检查SQL语句检查SQL语句的语法是否正确。②编译SQL语句。将SQL语句编译成可执行的函数。检查SQL和编译SQL花费的时间比执行SQL的时间还要长。如果我们只是重新设置参数,那么检查SQL语句和编译SQL语句将不需要重复执行。这样就提高了性能。③执行SQL语句

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Vue核心⑥(绑定样式)
下一篇:SpringBoot使用Async注解失效原因分析及解决(spring异步回调)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~