Statement和ResultSet
目录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。
他们的区别是:
名称 | Statement | PreparedStatement | CallableStatement |
---|---|---|---|
说明 | Statement 提供基本的 SQL 操作. 适合静态SQL语句, 且传入的 SQL 语句无法接受参数. | PreparedStatement 可以在 SQL 中传递参数, 适合多次使用的 SQL 语句. | CallableStatement 可以调用 PL/SQL 存储过程. |
使用 | select * from account | select * 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<User> list = new ArrayList<User>();
while (resultSet.next()) {
//每遍历一次, 就是1条记录, 就封装成一个User对象
User user = new User(resultSet.getInt("id"),
resultSet.getString("username"),
resultSet.getString("password"),
resultSet.getString("nickname")
);
list.add(user);
}
标签:JDBC,name,resultSet,ResultSet,Statement,SQL,id,String
From: https://www.cnblogs.com/likeguang/p/16991281.html