最近在学习JDBC,在处理SQL语句时,使用到了preparedstatement对SQL语句进行了预编译,然后就在网上搜了一些相关说法,但大都没有彻底说明白,所以总结以下文章,便于日后复习:以下仅仅是我个人的看法,请慎重参考;
目录
sql语句执行过程:
首先我们需要了解,一条sql语句从DateBase接收到最终执行完并返回结果,可以分为下面三个过程:
- 词法和语义解析
- 优化sql语句,制定执行计划
- 执行并返回结果
如何理解预编译:
当我们在项目中使用sql语句时,我们的一条sql语句可能会反复执行,或者每次执行的时候只有个别的值不同:update的set子句值不同,insert的values值不同
例如:
insert into score(id ,name,math,english,chinese)values(1,'tom', 67,88,95);
insert into score(id ,name,math,english,chinese)values(1,'jack',23,88,67);
上面两条语句:insert的values值不同;但是insert这条SQL语句的框架除了values的值不同,其他都是相同的;
然而我们执行一条语句需要经历三个阶段,如果每次都需要经过上面的词法语义解析、语句优化、制定执行计划等,那我们操作上万条语句时,效率就大大降低了。
预编译语句:
所谓预编译语句就是将这类语句中的值用占位符替代,可以视为将sql语句模板化或者说参数化 ;
insert into score(id ,name,math,english,chinese)values(?,?,?,?);
上面这样的处理,也可以避免SQL注入问题;在一开始我们对values中的值不做设置,而是使用?占位符来代替,最后使用setxxx()方法来一一设置;
mysql 预编译的好处,JDBC使用预编译SQL的好处:
1. 提高执行效率
PreparedStatement可以尽可能的提高访问数据库的性能,数据库在处理SQL语句时都有一个预编译的过程,而预编译对象就是把一些格式固定的SQL编译后,存放在内存池中即数据库缓冲池,当我们再次执行相同的SQL语句时就不需要预编译的过程了,只需DBMS运行SQL语句。所以当你需要执行Statement对象多次的时候,PreparedStatement对象将会大大降低运行时间,特别是的大型的数据库中,它可以有效的也加快了访问数据库的速度。
*** dbms是数据库管理系统DatabaseManagementSystem ***
2. 提高代码可读性、可维护性
使用占位符?代替参数,将参数与SQL语句分离出来,这样就可以方便对程序的更改和延续,同样,也可以减少不必要的错误。
3. 提高SQL执行的安全性
SQL注入攻击:是从客户端输入一些非法的特殊字符,从而使服务器端在构造SQL语句时仍能正确构造,从而收集程序和服务器的信息或数据。
比如在Web信息系统的登录入口处,要求用户输入用户名和密码,客户端输入后,服务器端根据用户输入的信息来构造SQL语句,在数据库中查询是否存在此用户名以及密码是否正确。假设使用上述例子中的表“user”构造SQL语句的Java程序可能是:
sql = "select * from user where user.id = '" + userID + "' and user.password = "' + userPassword + "'";
其中user.id, user.password是从用户输入的用户名及密码。如果用户和密码输的都是 '1' or '1'='1',则服务器端生成的SQL语句如下:
sql = "select * from user where user.id = '1' or '1'='1' and user.password = '1' or '1'='1'
这个SQL语句中的where字句没有起到数据筛选的作用,因为只要数据库中有记录,就会返回一个结果不为空的记录集,查询就会通过。上面的例子说明:在Web环境中,有恶意的用户会利用那些设计不完善的、不能正确处理字符串的应用程序。特别是在公共Web站点上,在没有首先通过PreparedStatement对象处理的情况下,所有的用户输入都不会直接传递给SQL语句。此外,在用户有机会修改SQL语句的地方,如HTML的隐藏区域或一个查询字符串上,SQL语句都不应该被显示出来;