引入PreparedStatement
需求:
- 键盘录入用户名和密码,模拟用户登录操作
- 后台—有一张user表:用户表
- 如果键盘录入的用户名和密码和数据库中user表中用户名和密码一致,登录成功!否则,“用户名或者密码错误”
使用Statement
public class StatementTest {
public static void main(String[] args) {
//创建键盘录入对象
Scanner sc = new Scanner(System.in) ;
//提示并录入数据
System.out.println("请输入用户名:");
String username = sc.nextLine() ;
System.out.println("请输入密码:");
String password = sc.nextLine() ;
//调用方法
boolean flag= isLogin(username,password) ;
if(flag) {
System.out.println("恭喜您,登录成功!");
}else {
System.out.println("登录失败,您的用户名或者密码有误!");
}
}
private static boolean isLogin(String username, String password) {
Connection conn = null ;
Statement stmt = null ;
ResultSet rs = null ;
try {
//获取数据库的链接对象
conn = JdbcUtils.getConnection() ;
//准备sql
//通过用户名和密码查询用户---查询某一条件记录---如果有内容:存在
String sql = "select * from user where username = '"+username+"' and password = '"+password+"' " ;
System.out.println(sql);
//获取执行对象:Statement
stmt = conn.createStatement() ;
//执行查询
rs = stmt.executeQuery(sql) ;
return rs.next(); //有有记录:返回true
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.close(rs, stmt, conn);
}
return false;
}
}
如图所示,用户密码严重不符合数据库的用户名和密码,但是还是登陆成功了
- 存在严重问题:SQL注入: 不安全的行为
- 用户名和密码完全不一致,依然可以登录成功!
Statement的弊端
- 执行效率差
每一次发送sql语句之前,获取Statement
executeUpdate(String sql)
executeQuery(String sql) - 存在安全漏洞:sql注入 存在字符串拼接导致的!
一旦后台被攻击,可以sql注入行为篡改数据!
使用PreparedStatement
public class PreparedStatementTest {
public static void main(String[] args) {
//创建键盘录入对象
Scanner sc = new Scanner(System.in) ;
//提示并录入数据
System.out.println("请输入用户名:");
String username = sc.nextLine() ;
System.out.println("请输入密码:");
String password = sc.nextLine() ;
//调用方法
boolean flag= isLogin(username,password) ;
if(flag) {
System.out.println("恭喜您,登录成功!");
}else {
System.out.println("登录失败,您的用户名或者密码有误!");
}
}
private static boolean isLogin(String username, String password) {
Connection conn = null ;
PreparedStatement stmt = null ; //预编译对象
ResultSet rs = null ;
try {
//获取数据库的链接对象
conn = JdbcUtils.getConnection() ;
//准备sql
//通过用户名和密码查询用户---查询某一条件记录---如果有内容:存在
//准备参数化的sql语句
//?:表示占位符号
String sql = "select * from user where username = ? and password = ?" ;
System.out.println(sql);
//获取预编译对象
//Connection
//PreparedStatement prepareStatement(String sql)
//将参数化的sql语句发送数据库进行预编译
stmt = conn.prepareStatement(sql) ;
//给占位符号赋值:参数赋值
//void setXXX(int parameterIndex,实际参数)
//参数1:?是第几个占位符
//参数2:实际参数
stmt.setString(1, username);
stmt.setString(2, password);
//执行查询/更新
//PreparedStatement:接口
//int executeUpdate()
//ResultSet executeQuery()
rs = stmt.executeQuery() ;
//执行查询
return rs.next(); //有有记录:返回true
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.close(rs, stmt, conn);
}
return false;
}
}
如图,使用PreparedStatement有效防止sql注入/可以提高开发效率