SQL注入
- 我们发现,按照上面的方法进行操作,无论密码是否正确,都提示我们登陆成功,这显然是不合理的。问题出在哪里呢?
- 字符串拼接后的SQL语句是:
select * from users where username = ‘kuangshen’ or 1 = 1 and password = ‘"+password+"’; - 运行到or的时候已经是条件成立,所以无论后面是否正确,无需验证密码即可登陆成功。
- 上面的问题都是通过在SQL语句中添加特殊的字符,构成关键字,改变了程序运行轨迹,从而对数据进行操作。
SQL注入问题:是指通过客户输入到后台的那些能到数据库得到数据的位置上,恶性的输入一些对数据有害的操作。
PreparedStatement
PreparedStatement对象介绍
- PreperedStatement是Statement的子类
- 它的实例对象可以通过调Connection.preparedStatement()方法获得,相对于Statement对象而言:PreperedStatement可以避免SQL注入的问题。
- Statement会使数据库频繁编译SQL,可能造成数据库缓冲区溢出。PreparedStatement可对SQL进行预编译,从而提高数据库的执行效率。
- 并且PreperedStatement对于sql中的参数,允许使用占位符的形式进行替换,简化sql语句的编写。
演示:
使用PreparedStatement对象完成对数据库的CRUD操作
案例:
package com.kuang.dao;
import com.kuang.utils.JDBCUtils;
import java.sql.*;
import java.util.Scanner;
//防止SQL注入
public class Demo03 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
//1.获取数据库连接
connection = JDBCUtils.getConnection();
//prepareStatement解决sql注入问题
//select * from users where id = 1
//System.out.print("请输入你要查询的用户名:");
//String username = scanner.nextLine();
/*
preparedStatement【推荐使用】 和 Statement;
相同点 : 都是用来执行sql语句的
不同点 :
Statement 不安全 , 不能预编译SQL , 不能使用占位符 , 容易造成SQL语句拼接错误
preparedStatement 安全 , 预编译SQL语句 , 可以使用 ? 占位符 ,SQL更清晰。
如何给preparedStatement的占位符赋值
preparedStatement.setXXX [xxx:对应占位符数据的类型] (?索引[从1开始] , 传入的值)
Statement 先写SQL语句再执行; Statement.execute(SQL)
preparedStatement 直接编译SQL , 调用方法执行 ; preparedStatement.execute();
*/
preparedStatement = connection.prepareStatement("select * from users where id = ? and name = ?");
preparedStatement.setInt(1,4);
preparedStatement.setString(2,"qinjiang");
//preparedStatement.setString(1,username);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()){
System.out.println(resultSet.getString("name"));
System.out.println(resultSet.getString("password"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
//5.释放资源
JDBCUtils.closeAll(resultSet,preparedStatement,connection);
}
}
}
事务
案例:
package com.kuang.dao;
import com.kuang.utils.JDBCUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Demo04 {
/*
事务 : 一组sql语句要么都成功,要么都失败;
开启事务 setAutoCommit(false);
提交事务 commit ;
回滚事务 rollback ;
#开启事务后 , 如果不提交事务 , 那么所有的操作在mysql连接断开后,会回复到最开始的样子;
#开启事务后 , 更新了数据 , 不想更新了 , 可以选择回滚;
*/
public static void main(String[] args) throws SQLException {
Connection connection = JDBCUtils.getConnection();
//start transaction
connection.setAutoCommit(false); //关闭数据库的事务自动提交 = 通知数据库开启事务控制;
String sql = "update account set money = money - 100 where name='A'";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.execute();
connection.rollback();
//connection.commit(); //提交事务
JDBCUtils.closeAll(null,preparedStatement,connection);
}
}