区别:
(1)#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如: #{id},如果传入的值是id,则解析成的sql为"id"。
(2)$将传入的数据直接显示生成在sql中。如:${id},如果传入的值是id,则解析成的sql为id。
(3)#方式在很大程度上能够防止sql注入。
(4)$方式无法防止sql注入。
(5)$方式一般用于传入数据库对象,例如传入表名。(这里得注意SQL注入问题)
(6)一般能用#的就别用$。
ps:在使用mybatis中还遇到<![CDATA[]]>的用法,在该符号内的语句,将不会被当成字符串来处理,而是直接当成sql语句,比如要执行一个存储过程。
总结区别:#{} 传入值时,sql解析时,参数是带引号的,而${}传入值,sql解析时,参数是不带引号的。
举个例子:
select * from ${tableName} where XX = #{XX}
在这个例子中,如果表名为
hsics.abcd --
则动态解析之后 sql 如下:
select * from hsics.abcd-- where name = ?;
–之后的语句被注释掉。
但是表名用参数传递进来的时候,只能使用 ${} 。这也提醒在这种用法中要小心sql注入的问题。
防止SQL注入方法:
首先,永远不要相信用户的输入。
(1)正则表达式,字符串过滤。
(2)参数绑定PreparedStatement(见下面解释)。
(3)使用正则表达式过滤传入的参数。
(4)JSP中调用该函数检查是否包函非法字符或JSP页面判断代码。JSP参考JSP使用过滤器防止SQL注入
PreparedStatement:
PreparedStatement是用来执行SQL查询语句的API之一,Java提供了 Statement、PreparedStatement 和 CallableStatement三种方式来执行查询语句,其中 Statement 用于通用查询, PreparedStatement 用于执行参数化查询,而 CallableStatement则是用于存储过程。
PreparedStatement是java.sql包下面的一个接口,用来执行SQL语句查询,通过调用connection.preparedStatement(sql)方法可以获得PreparedStatment对象。数据库系统会对sql语句进行预编译处理(如果JDBC驱动支持的话),预处理语句将被预先编译好,这条预编译的sql查询语句能在将来的查询中重用,这样一来,它比Statement对象生成的查询速度更快。
PreparedStatement如何防止SQL注入式攻击:
恶意注入:
userName = "1' OR '1'='1"; passWord = "1' OR '1'='1";
那么最终SQL语句变成了:SELECT * FROM users WHERE name = '1' OR '1'='1' and pw = '1' OR '1'='1';
相当于SELECT * FROM users;
可以达到无账号密码亦可登录网站。
使用PreparedStatement的参数化的查询可以阻止大部分的SQL注入。在使用参数化查询的情况下,数据库系统(eg:MySQL)不会将参数的内容视为SQL指令的一部分来处理,而是在数据库完成SQL指令的编译后,才套用参数运行,因此就算参数中含有破坏性的指令,也不会被数据库所运行。
在组合SQL字符串的时候,先对所传入的参数做字符取代(将单引号字符取代为连续2个单引号字符,因为连续2个单引号字符在SQL数据库中会视为字符中的一个单引号字符,譬如:SELECT * FROM users WHERE name = ' " + userName + " ';
传入字符串userName = " 1' OR 1=1 "
把userName做字符替换后变成userName = " 1'' OR 1=1"
最后生成的SQL查询语句为:SELECT * FROM users WHERE name = '1'' OR 1=1'
这样数据库就会去系统查找name为" 1 ’ ’ OR 1=1 " 的记录,而避免了SQL注入。
经过试验,确实如此:
PreparedStatement部分我是看了这篇文章的:
http://www.importnew.com/5006.html