用JDBC里的preparedstatement的好处
举个例子,假如我们在做用户的登录认证,里面有两个字段username,passwword,我们如果用字符串拼接,我们一般这么写:“select id from users where username = '”+username +"’ and password = ‘" + password +"’" 这里的username和password都是我们存取从web表单获得的数据。如果我们在字符串上面输入
'or 1 = 1’那么意味着我根本不用管他的数据库,直接可以通过验证,password我写一个简单的123,这时候
select id from users where username = ‘’ or 1=1-- and password = ‘123’,这好吗,这不好。这就是简单的sql注入
但是preparedstatement传参数的时候用占位符"?"解决了这个问题
import java.io.IOException; public class TestMark_to_win { public static void main(String[] args) throws java.sql.SQLException, ClassNotFoundException, IOException { int i = 0; java.sql.Connection connection = null; java.sql.PreparedStatement pstmt; Class.forName("com.mysql.jdbc.Driver"); connection = java.sql.DriverManager.getConnection( "jdbc:mysql://localhost:3306/test", "root", "1234"); pstmt = connection .prepareStatement("UPDATE login SET name = ? WHERE id = ?"); long t = System.currentTimeMillis(); for(i=0;i<10000;i++) { pstmt.setString(1, "qqqq"); pstmt.setString(2, "2"); pstmt.executeUpdate(); } t = System.currentTimeMillis() - t; System.out.println("用了如下时间:" + t); pstmt.close(); System.out.println("ok"); connection.close(); } }
如果用字符串拼接。当一个数据库收到一个statement后,数据库引擎会先解析statement,然后检查其是否有语法错误。一旦statement被正确的解析,数据库会选出执行statement的最优途径。遗憾的是这个计算开销非常昂贵。数据库会首先检查是否有相关的索引可以对此提供帮助,不管是否会将一个表中的全部行都读出来。数据库对数据进行统计,然后选出最优途径。当决创建查询方案后,数据库引擎会将它执行。
数据库已经具有了类似的功能。它们通常会用如下方法对statement进行缓存。使用statement本身作为key并将存取方案存入与statement对应的缓存中。这样数据库引擎就可以对曾经执行过的statements中的存取方案进行重用。举个例子,如果我们发送一条包含SELECT a, b FROM t WHERE c = 2的statement到数据库,然后首先会将存取方案进行缓存。当我们再次发送相同的statement时,数据库会对先前使用过的存取方案进行重用,这样就降低了CPU的开销。
那么,当c = 3的时候,那么缓冲区没有了就会自己去编译
那么PareparedStatement就像是一个没吃过饭的用户,他点的的食物很多而且都是准备好的,所以在准备做菜的时候会有开销,一旦运行起来它的效果是非常好的,所以.PreparedStatement是预编译的,对于批量处理可以大大提高效率
结论: prepareStatement会先初始化SQL,先把这个SQL提交到数据库中进行预处理,多次使用可提高效率。 createStatement不会初始化,没有预处理,没次都是从0开始执行SQL
那么什么时候preparedstatement效果会比字符串拼接差,这得问老师