java JDBC 编程之ResultSet , Statement 和 PrepareStatement
这里写自定义目录标题
ResultSet[结果集]
基本介绍
- 表示数据库结果集的数据表,通常通过执行查询数据库的指令生成
- ResultSet 对象持有一个光标指向当前数据行,最初光标位于第一行之前
- next() 方法将光标移向下一行,当没有更多行的时候返回false,因此可以用while循环来遍历结果集
案例
演示查询数据库jdbc中的actor表,返回actor表的id,name,sex,borndate 列
public static void main(String[] args) throws IOException, ClassNotFoundException, SQLException {
//获取配置信息
Properties properties = new Properties();
properties.load(new FileReader("src/mysql.properties"));
String url=properties.getProperty("url");
String user=properties.getProperty("user");
String password=properties.getProperty("password");
String driver=properties.getProperty("driver");
//利用反射加载Driver类
Class.forName(driver);
//获取连接
Connection connection = DriverManager.getConnection(url, user, password);
//发送sql查询语句
//查询数据库jdbc中的actor表,返回actor表的id,name,sex,borndate 列
//结果应为:
/*
+----+------+-----+---------------------+
| id | name | sex | borndate |
+----+------+-----+---------------------+
| 1 | tom | 男 | 2001-10-05 00:00:00 |
| 2 | jack | 男 | 2002-02-25 00:00:00 |
+----+------+-----+---------------------+
*/
String select="select id, name, sex, borndate from actor;";
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(select); //返回查询过后的结果集(也就是表的数据)
//对resultSet 遍历得到数据
// 可以认为在resultSet对象中,有一个光标指向表头,resultSet.next()就是把光标移向下一行,如果到头了,就返回false
while (resultSet.next()){
int id = resultSet.getInt(1);//得到表的第一列数据,由于第一返回的第一列是id ,所以用整型来接收
String name = resultSet.getString(2);
String sex = resultSet.getString(3);
Date borndate = resultSet.getDate(4);
System.out.println("\t"+id+"\t"+name+"\t"+sex+"\t" +borndate+"\t");//打印数据
}
//关闭连接
resultSet.close();
statement.close();
connection.close();
}
输出:
1 tom 男 2001-10-05
2 jack 男 2002-02-25
Statement
基本介绍:
- Statement 用于执行静态的sql语句,并返回其生成的结果的对象.
- 在连接建立后,需要对数据库进行访问,执行,命名或是sql语句,可以通过:
Statement [存在SQL注入]
PreparedStatement [预处理]
CallableStatement [存储过程] - Statement对象执行sql语句,存在SQL注入风险
- SQL注入是指某些系统没有对用户输入的数据进行充分的检查,而在用户的输入数据中执行非法的sql语句,攻击数据库
- 要防范SQL注入,只要用PreparedStatement(Statement扩展而来)来取代Statement就好了
演示SQL注入:
//演示SQL注入
public static void main(String[] args) throws IOException, ClassNotFoundException, SQLException {
//获取配置信息
Properties properties = new Properties();
properties.load(new FileReader("src/mysql.properties"));
String url=properties.getProperty("url");
String user=properties.getProperty("user");
String password=properties.getProperty("password");
String driver=properties.getProperty("driver");
//利用反射加载Driver类
Class.forName(driver);
//获取连接
Connection connection = DriverManager.getConnection(url, user, password);
//获取用户输入的用户名和密码
//这里只有用户名是tom,密码是123是合法的
Scanner input = new Scanner(System.in);
System.out.print("请输入用户名: ");
String user_name = input.nextLine();
System.out.print("请输入密码: ");
String user_password=input.nextLine();
//执行sql语句
String select ="select * from admin where `user`='"+user_name+
"' and pwd='"+user_password+"';";
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(select);
if(resultSet.next()){//如果查询到了数据,就打印登录成功,否则登录失败
System.out.println("登录成功");
}
else {
System.out.println("该用户不存在...");
}
}
上面这段代码要求用户输入用户名和密码,如果查询到用户输入的用户名和密码,就提示登录成功,否则提示该用户不存在.
如果像下面这样输入,则会提示登录成功:
请输入用户名: tom
请输入密码: 123
登录成功
如果像下面这样输入,则会提示该用户不存在:
请输入用户名: jack
请输入密码: 123
该用户不存在...
如果像下面这样输入,也会提示登录成功,但数据库中并没有该用户,于是就被SQL注入了:
请输入用户名: 1' or
请输入密码: or '1'='1
登录成功
PrepareStatement [预处理]
基本介绍:
- PreparedStatement执行的SQL语句的参数用"?"表示,调用PreparedStatement对象的setXxx()方法来设置这些参数, setXxx()方法有两个参数,第一个参数是设置sql语句中参数的索引(从1开始),第二个参数是设置sql语句参数的值
- 执行查询语句,调用executeQuery()方法返回ResultSet对象
- 执行更新(增,删,修改),调用executeUpdate()方法
预处理好处
- 不再使用+拼接SQL语句
- 有效解决了SQL注入问题
- 大大减少了编译次数,提高了效率
示例
//PrepareStatement演示
public static void main(String[] args) throws IOException, ClassNotFoundException, SQLException {
//获取配置信息
Properties properties = new Properties();
properties.load(new FileReader("src/mysql.properties"));
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String url = properties.getProperty("url");
String driver = properties.getProperty("driver");
//注册驱动
Class.forName(driver);
//获取连接
Connection connection = DriverManager.getConnection(url, user, password);
//获取用户输入
Scanner input = new Scanner(System.in);
System.out.print("请输入用户名: ");
String user_name = input.nextLine();
System.out.print("请输入密码: ");
String user_password=input.nextLine();
//发送SQL语句
//在使用PereparedStatement的对象(实际上是实现了preparedStratement接口的类的对象)发送sql语句时,要用"?"做占位符
String sql="select `user`,pwd from `admin` where `user`=? and `pwd`=?;";
//在这里就将sql语句传入,以便对"?"做处理
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//用实际值填充占位符"?",第一个参数是:要填入数据的占位符"?"的位置(从1开始),第二个参数是数据
preparedStatement.setString(1,user_name);
preparedStatement.setString(2,user_password);
//执行查询语句,使用executeQuery方法,返回结果集.(这里的实参不要填入sql语句,如果填入会将带"?"的sql语句填入,出现异常)
//如果执行dml(插入,删除,更改)语句,用executeUpdate方法
ResultSet resultSet = preparedStatement.executeQuery();
if(resultSet.next()){
System.out.println("登录成功");
}
else {
System.out.println("登录失败");
}
//关闭连接
resultSet.close();
preparedStatement.close();
connection.close();
}
当想做SQL注入时,结果无法成功
请输入用户名: 1' or
请输入密码: or '1'='1
登录失败