在Java中执行SQL语句的过程中,由于用户提供的信息中含有SQL关键字,进行编译的过程中,会扭曲原SQL语句的含义,所以我们应当避免SQL语句的注入,那么如何避免呢?
先定义SQl语句框架,对SQL语句进行预先编译,只编译一次,然后再去接收用户提供的信息;
* 用户提供的信息即使含有SQL语句的关键字,这些关键字不参与这次SQL语句的编译,是不起作用的。
* 采用这种方式可以解决SQL注入问题
* 有的系统中是需要SQL注入的,这个时候必须使用java.sql.Statement;
* 有的系统不需要SQL注入的,这个时候必须使用java.sql.PreparedStatement;
PreparedStatement的优点:
* 1.可以防止SQL注入;
* 2.SQL语句对Statement来说是编译一次执行一次;编译N次执行N次。
* 但SQL语句对于PreparedStatement来说是编译一次,执行N次。所以PreparedStatement执行效率更高
* 3.PreparedStatement是类安全型。【编译期检查数据类型】
改进后等用户登陆代码如下:
public class JDBCTest06 {
public static void main(String[] args)throws Exception {
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
System.out.println("请登陆");
System.out.println("用户名:");
String username=br.readLine();
System.out.println("密码:");
String userpwd=br.readLine();
br.close();
//调用登陆方法登陆
login(username,userpwd);
}
public static void login(String username, String userpwd) {
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
boolean LoginSuccess=false;
try {
//1注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2获取连接
conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","123");
//3获取预编译的数据库对象
String sql="select * from tbl_user where username=? and userpwd=?";//先定义SQL语句的框架
ps=conn.prepareStatement(sql);//执行到此处,现将SQL语句框架进行预编译
//给??复制
ps.setString(1,username);
ps.setString(2, userpwd);
//4执行SQL语句
rs=ps.executeQuery();
//5处理结果集
if(rs.next()){
LoginSuccess=true;
}
} catch (Exception e) {
e.printStackTrace();
}finally{//6释放资源
if(rs!=null){try {
rs.close();
} catch (SQLException e){
e.printStackTrace();
}}
if(ps!=null){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
System.out.println(LoginSuccess?"登录成功":"登陆失败");
}
}