Statement和PreparedStatement的区别
联系
- PreparedStatement继承自Statement,两者都是接口。
- Statement 用于执行静态SQL 语句在执行时,必须指定一个事先准备好的SQL语句。
- PreparedStatement 是预编译的SQL语句对象,sql语句被预编译并保存在对象中。被封装的sql语句代表某一类操作,语句可以包含动态的参数 “ ?”,执行时可以为“ ? ”动态设置参数值。
- 使用PreparedStatement对象执行sql时,sql语句被数据库进行解析和编译,然后被放到命令缓存区,每当执行同一个PreparedStatement 对象时,它就会被解析一次,但不会被再次编译。在缓存区可以发现预编译的sql命令,并且可以重用。
- PreparedStatement 可以减少编译次数提高数据库性能。
防止SQL注入
方法一:创建Statement对象
例如:
1.Class.forName(com.mysql.jdbc.Driver);//加载驱动
2.Connection conn=DriverManager.getConnection("jdbc:mysql//:....")//创建与某个数据库的连接
3.Statement stmt=conn.CreateStatement();//创建一个statementd对象
4.String id=01;
5.String sql="delete from table where id='"+id+"'";//构建SQL语句
6.stmt.executeUpdate(sql);//执行SQL语句
上面的这段代码的本意是想删除在数据库里删除 id=01 的记录,但是如果有人将 id 的内容改为 " 01 or 1=1" 时,数据库在接收到命令后,无论你输入是否存在都会执行,因为数据库会把 " or 1=1"当成判断条件,所以无论如何该语句都会执行。那么表中的任何记录都将被删除,后果会非常严重。
缺点:
- 不能防止sql 注入,安全性低
- 每次执行都需要重新编译sql语句,效率低下。
方法二:创建PreparedStatement对象
1.Class.forName(com.mysql.jdbc.Driver);//加载驱动
2.Connection conn=DriverManager.getConnection("jdbc:mysql//:....")//创建与某个数据库的连接
3.String sql="delete from table where id=?";//构建SQL语句,设置占位符
4.PreparedStatement ps=conn.PreparedStatement(sql);//创建PreparedStatement时传入sql语句,实现预编译
5.ps.setInt(1,"01");//设置sql语句的占位符的值,注意第一个参数为1
6.ps.executeUpdate();//执行SQL语句
为什么PreparedStatement能防止sql注入呢???
因为sql 语句是预编译的,而且语句中使用了占位符,规定了sql语句的结构。并且如果输入" 01 or 1=1"时,数据库会把" 01 or 1=1"当成值,而不是"1=1" 当成判断条件,所以能防止sql注入。
实际开发中,建议使用PreparedStatement访问数据库,因为它不仅能防止sql注入,安全性提高;而且是预编译的 ,不用每执行一次都需要重新编译SQL语句,效率高;另外,它执行语句得到的结果是离线的,连接关闭后,仍然可以访问结果集。