5. PreparedStatement:执行sql的对象
1.以上问题是 SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题
1. 输入用户随便,输入密码:a' or 'a' = 'a
2. sql:select * from user where username = 'fhdsjkf' and password = 'a' or 'a' = 'a'
where username = 'fhdsjkf' and password = 'a' or 'a' = 'a' --》flase or true=true 所以这里会有bug
2. 解决sql注入问题:使用PreparedStatement对象来解决
与statement类似也是执行sql语句的方法
获取执行sql的对象 Statement stmt = conn.createStatement();
3. 预编译的SQL:参数使用?作为占位符
4. 步骤:
1. 导入驱动jar包 mysql-connector-java-5.1.37-bin.jar
2. 注册驱动
3. 获取数据库连接对象 Connection
4. 定义sql
* 注意:sql的参数使用?作为占位符。 如:select * from user where username = ? and password = ?;
5. 获取执行sql语句的对象 PreparedStatement Connection.prepareStatement(String sql)
6. 给?赋值:
* 方法: setXxx(参数1,参数2)
* 参数1:?的位置编号 从1 开始
* 参数2:?的值
7. 执行sql,接受返回结果,不需要传递sql语句 获取对象时候就传递了sql语句
8. 处理结果
9. 释放资源
5. 注意:后期都会使用PreparedStatement来完成增删改查的所有操作
1. 可以防止SQL注入
2. 效率更高
注意这种方法是主要用的
后期都会使用PreparedStatement来完成增删改查的所有操作
增删改查 这里是查
package cn.itcast.jdbc;
import cn.itcast.utils.JdbcUtils;
import java.sql.*;
import java.util.Scanner;
/*
* 需求:
1. 通过键盘录入用户名和密码
2. 判断用户是否登录成功
*/
public class JdbcDemo11 {
public static void main(String[] args) {
//1.键盘录入 接受用户名和密码
Scanner sc= new Scanner(System.in);
System.out.println("请输入用户名");
String username = sc.nextLine();
System.out.println("请输入密码");
String password = sc.nextLine();
//2.调用方法 返回Boolean
boolean flag = new JdbcDemo11().login02(username,password);
//3.判断结果 输出语句
if (flag=true){
System.out.println("登陆成功");
}else{
System.out.println("用户名或者密码错误");
}
}
//登录方法
public static boolean login02(String username, String password){
if (username==null&&password==null){
return false;
}
/*连接数据库来判断是否登陆成功
* select * from user where username = '"+username+"' and password = '"+password+"';
* 如果这个sql有查询结果,则成功,反之,则失败
*/
//1.获取数据库连接
Connection conn=null;
PreparedStatement pstmt=null;
ResultSet rs=null;
try {
conn = JdbcUtils.getConnection();
//2.定义sql
String sql = "select * from user where username = ? and password = ?";
//3.获取执行sql的对象
pstmt = conn.prepareStatement(sql);
//给问号赋值
pstmt.setString(1,username);
pstmt.setString(2,password);
//4、执行查询 返回结果集resultSet对象
rs = pstmt.executeQuery(); //这里不需要传递sql了
//5.判断
/*if (rs.next()){ //如果有下一行则返回true
return true;
}else{
return false; //
}*/
return rs.next(); //游标下移一行有数据true 无数据返回false
} catch (SQLException e) {
e.printStackTrace();
}finally{
JdbcUtils.close(rs,pstmt,conn);
}
return false; //这里的false相对与上面的如果出现了异常就返回这个false 因为之前的先判断
}
}
jdbcutils工具类
package cn.itcast.utils;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.sql.*;
import java.util.Properties;
/*
Jdbc工具类
*/
public class JdbcUtils {
private static String url; //把这三个本来是局部变量的变量作用域提升
private static String user;
private static String password;
private static String driver;
//这里为什么是静态的成员变量呢 因为只有静态的成员变量和成员方法才能被静态代码段所访问
/*
文件的读取,只需要读取一次即可拿到这些值"jdbc:mysql:///db3","root","root" 使用静态代码块
*/
static {//静态代码块
try {
//读取资源文件 获取值 获取的值给getConnection()方法用
//1.创建Properties集合类
Properties pro = new Properties();
//2.加载文件
//pro.load(new FileReader("src/jdbc.properties"));
//这里之前报错 解决方法一上面地址写绝对地址
// 方法二是采用获取src路径下的文件的方式--》ClassLoader类加载器
ClassLoader classLoader = JdbcUtils.class.getClassLoader(); //classloader类加载器
URL res = classLoader.getResource("jdbc.properties"); //返回的Url是一个统一资源定位符 可以定位一个文件的绝对路径
String path = res.getPath(); //使用getPath();方法获取到绝对路径 可以sout看一下路径 得到的就是绝对路径
pro.load(new FileReader(path));
//3.获取属性赋值
url = pro.getProperty("url");
user = pro.getProperty("user");
password = pro.getProperty("password");
driver = pro.getProperty("driver");
//4.注册驱动
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//获取连接的方法
public static Connection getConnection() throws SQLException {
//成员方法 返回值是一个Connection类型的数据
//获取连接的方法 返回的是连接对象
// 工具类有一个特点所有的方法都是静态的方法方便来调用 所以这里做一个静态方法加static
return DriverManager.getConnection(url,user,password);
}
//释放资源的方法
/**
* 定义释放资源的方法
* 使用增删改要释放 connection和statement 对象
* 使用查询时候还要释放一个 ResultSet对象
* 所以这里写两个动作 使用重载的机制
*/
public static void close(Statement stmt, Connection conn) {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 重载close方法
*/
public static void close(ResultSet rs, Statement stmt, Connection conn) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}