联系:
1.PreparedStatement和Statement都是用来执行SQL查询语句的API之一
2.PreparedStatement接口继承了Statement接口
区别:
1.防注入
Class.forName(com.mysql.jdbc.Driver);
Connection con = DriverManager.getConnection("jdbc:mysql://....");
Statement st = con.CreateStatement();
String id = "20221101";
String sq = "delete from table1 where id="+id;
st.execute(sq);
上面这段代码的本意是要删除id=20221101的记录,但是如果有人将id的内容改为“20221101 or 1=1”。
那么表中的任何记录都将被删除,后果十分严重。
再比如登录界面用户可以在输入密码的时候加上两个冒号作为特殊字符利用布尔恒等式,“paasword or '1=1'”,
这样的话会让计算机认为他输入的是SQL语句的关键字从而改变你的SQL语句,
造成不可估量的损失。
为什么PreparedStatement能防止sql注入呢?
因为sql语句是预编译的,而且语句中使用了占位符,规定了sql语句的结构。
用户可以设置"?"的值,但是不能改变sql语句的结构,
因此想在sql语句后面加上如“or 1=1”(1=1能查出全部用户)等奇怪字符串的拼接来实现sql注入是行不通的。
PreparedStatement 防止 SQL 注入的原理就是把用户非法输入的单引号进行转义,最终传入参数作为一个整体执行,从而防止 SQL 注入,而 Statement 对象不会进行此操作。
2.预编译
实际开发中,一般采用PreparedStatement访问数据库,它不仅能防止sql注入,还是预编译的(不用改变一次参数就要重新编译整个sql语句,效率高)、Statement每次执行都需要重新编译sql语句,效率低下。而PreparedStatement则解决了这些问题。PreparedStatement会将编译好的sql语句放在数据库端,相当于缓存。对于多次重复执行的sql语句,使用PreparedStatement可以使得代码的执行效率更高。
此外,它执行查询语句得到的结果集是离线的,连接关闭后,仍然可以访问结果集。
3.可读性
Statement的sql语句使用字符串拼接的方式,容易导致出错,PreparedStatement使用“?”占位符提升代码的可读性和可维护性,并且这种绑定参数的方式,可以有效的防止sql注入。
综上,PreparedStatement 可以有效防止 SQL 注入,且采用预编译模式,你应该始终以 PreparedStatement 代替 Statement,也就是说,在任何时候都不要使用 Statement。