热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

JDBC之Statement和ResultSet

Statement和ResultSet目录Statement和ResultSetStatementStatement概述要执行的SQL分为两类查询增删改Statement继承体系S

Statement和ResultSet

目录



  • Statement和ResultSet

    • Statement

      • Statement概述

      • 要执行的SQL分为两类

        • 查询

        • 增删改



      • Statement继承体系

        • SQL注入问题

        • SQL注入问题解决





    • ResultSet

      • 单值

      • 多值

      • 重点

        • 游标

        • get方法



      • 使用示例






Statement


Statement概述

接口的实现在数据库驱动中. 用来操作sql语句(增删改查),并返回相应结果对象

JDBC利用Statement把将要执行的SQL发送给MySQL服务端进行操作。

JDBC利用Statement把将要执行的SQL发送给MySQL服务端进行操作。

JDBC利用Statement把将要执行的SQL发送给MySQL服务端进行操作。

JDBC想要利用SQL完成对数据库的增删改查,只需要通过Statement这个对象向数据库发送增删改查对应的SQL语句即可。


要执行的SQL分为两类


查询

Statement.executeQuery方法用于向数据库发送查询语句,executeQuery方法返回代表查询结果的ResultSet对象。


增删改

Statement对象的executeUpdate方法,用于向数据库发送增、删、改的sql语句,executeUpdate执行完后,将会返回一个整数(即增删改对应的SQL语句导致了数据库有几行数据发生了变化)。


Statement继承体系

其中 CallableStatement 继承自 PreparedStatement, 而 PreparedStatement 又继承自 Statement。

他们的区别是:































名称StatementPreparedStatementCallableStatement
说明Statement 提供基本的 SQL 操作. 适合静态SQL语句, 且传入的 SQL 语句无法接受参数.PreparedStatement 可以在 SQL 中传递参数, 适合多次使用的 SQL 语句.CallableStatement 可以调用 PL/SQL 存储过程.
使用select * from accountselect * from account where id = ?
额外说明静态SQL,因为没有动态参数动态SQL
可以防止SQL注入
不做了解,因为阿里巴巴规范中强制要求不要使用存储过程

SQL注入问题

下面先看下SQL注入出现的原因,代码如下:

public class SqlInjectTest {
public static void main(String[] args) throws SQLException {
String url = "jdbc:mysql://localhost:3306/mysql_index_test?useSSL=true";
Properties properties = new Properties();
properties.setProperty("user","root");
properties.setProperty("password","root");
Connection cOnnection= DriverManager.getConnection(url, properties);
Statement statement = connection.createStatement();
// 后面的参数1假如是用户传递的
String paremeter = "1";
String sql = "select * from film where id = " + paremeter;
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()){
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
System.out.println(String.format("id是:%s,name是:%s",id,name));
}
resultSet.close();
statement.close();
connection.close();
}
}

查询结果如下:

id是:1,name是:film1

但是如果被有些别出心裁的人知道了SQL语句是这样子拼接的时候,那么可以伪造SQL,如下所示:

public class SqlInjectTest {
public static void main(String[] args) throws SQLException {
String url = "jdbc:mysql://localhost:3306/mysql_index_test?useSSL=true";
Properties properties = new Properties();
properties.setProperty("user","root");
properties.setProperty("password","root");
Connection cOnnection= DriverManager.getConnection(url, properties);
Statement statement = connection.createStatement();
// 后面的参数1假如是用户传递的
String paremeter = "1 or 1=1";
String sql = "select * from film where id = " + paremeter;
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()){
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
System.out.println(String.format("id是:%s,name是:%s",id,name));
}
resultSet.close();
statement.close();
connection.close();
}
}

对应的结果如下所示:

id是:3,name是:film0
id是:1,name是:film1
id是:2,name是:film2

SQL注入问题解决

本质原因是因为上面使用的Statement是原生的,那么我们需要使用预编译的PreparedStatement解决问题

代码如下所示:

public class SqlInjectTest {
public static void main(String[] args) throws SQLException {
String url = "jdbc:mysql://localhost:3306/mysql_index_test?useSSL=true";
Properties properties = new Properties();
properties.setProperty("user","root");
properties.setProperty("password","root");
Connection cOnnection= DriverManager.getConnection(url, properties);
// 后面的参数1假如是用户传递的
String paremeter = "film0";
String sql = "select * from film where name = ?" ;
PreparedStatement statement = connection.prepareStatement(sql);
// 设置第1个?的值是paremeter
statement.setString(1,paremeter);
ResultSet resultSet = statement.executeQuery();
while (resultSet.next()){
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
System.out.println(String.format("id是:%s,name是:%s",id,name));
}
resultSet.close();
statement.close();
connection.close();
}
}

那么再看一下另外一种情况

public class SqlInjectTest {
public static void main(String[] args) throws SQLException {
String url = "jdbc:mysql://localhost:3306/mysql_index_test?useSSL=true";
Properties properties = new Properties();
properties.setProperty("user","root");
properties.setProperty("password","root");
Connection cOnnection= DriverManager.getConnection(url, properties);
// 后面的参数1假如是用户传递的
String paremeter = "film0 or 1=1";
String sql = "select * from film where name = ?" ;
PreparedStatement statement = connection.prepareStatement(sql);
// 设置第1个?的值是paremeter【根据对应的数据类型来进行设置】
statement.setString(1,paremeter);
ResultSet resultSet = statement.executeQuery();
while (resultSet.next()){
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
System.out.println(String.format("id是:%s,name是:%s",id,name));
}
resultSet.close();
statement.close();
connection.close();
}
}

没有结果!!!

因为对应的SQL已经被修改了,变成了

select * from film where name = 'film0 or 1=1'

而不是我们想象的

select * from film where name = 'film0' or 1=1

所以上面的查询是没有结果的,因为在数据库中根本就没有找到这样的name


ResultSet

从名字上就可以看到是结果集,表示的是查询出来的结果集。

JDBC用ResultSet来封装结果集,查询结果表的对象。

查询结果分为两种情况:


单值

单个结果,比如说SQL如下:

select count(*) from account;
select max(id) from account;
select min(id) from account;

查询出来的是一个数字


多值

普遍来说是多个字段,这个时候对象就可以发挥效果。

select id,name,address from account where id = 1;

重点


游标

在ResultSet有一个游标的概念

提供一个游标,默认游标指向结果集第一行之前。调用一次next(),游标向下移动一行。提供一些get方法。

根据while循环的使用经验,如果不知道有多少条,那么使用while进行判断即可。


get方法

既然获取出来的有结果,那么就需要得到对应的值。ResultSet也提供了对应的方法

ResultSet接口常用API



  • boolean next();将光标从当前位置向下移动一行

  • int getInt(int colIndex)以int形式获取ResultSet结果集当前行指定列号值

  • int getInt(String colLabel)以int形式获取ResultSet结果集当前行指定列名值

  • float getFloat(int colIndex)以float形式获取ResultSet结果集当前行指定列号值

  • float getFloat(String colLabel)以float形式获取ResultSet结果集当前行指定列名值

  • String getString(int colIndex)以String 形式获取ResultSet结果集当前行指定列号值

  • String getString(String colLabel)以String形式获取ResultSet结果集当前行指定列名值

  • Date getDate(int columnIndex); 以Date 形式获取ResultSet结果集当前行指定列号值

  • Date getDate(String columnName);以Date形式获取ResultSet结果集当前行指定列名值

  • void close()关闭ResultSet 对象


使用示例

public class User implement Serializable{
private int id;
private String username;
private String password;
private String nickname;
//提供get/set/toString方法 Alt+Insert
}

对应的JDBC代码如下所示

List list = new ArrayList();
while (resultSet.next()) {
//每遍历一次, 就是1条记录, 就封装成一个User对象
User user = new User(resultSet.getInt("id"),
resultSet.getString("username"),
resultSet.getString("password"),
resultSet.getString("nickname")
);
list.add(user);
}

从理论中来,到实践中去,最终回归理论



推荐阅读
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 原文地址:https:www.cnblogs.combaoyipSpringBoot_YML.html1.在springboot中,有两种配置文件,一种 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • C语言注释工具及快捷键,删除C语言注释工具的实现思路
    本文介绍了C语言中注释的两种方式以及注释的作用,提供了删除C语言注释的工具实现思路,并分享了C语言中注释的快捷键操作方法。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • 本文介绍了一种划分和计数油田地块的方法。根据给定的条件,通过遍历和DFS算法,将符合条件的地块标记为不符合条件的地块,并进行计数。同时,还介绍了如何判断点是否在给定范围内的方法。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
author-avatar
甜甜M雪糕
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有