一、使用 + 号进行拼接。
SELECT * FROM users WHERE id = 1 + 2;
在 SQL 语句中,+ 号用于进行字符串拼接,相当于将两个字符串连接在一起。在上面的 SQL 语句中,1 和 2 会先进行数值运算,然后再拼接成字符串,最终的 SQL 语句等价于:
SELECT * FROM users WHERE id = 3;
二、使用 CONCAT 函数进行拼接。
SELECT * FROM users WHERE name = CONCAT('a', 'b');
在 SQL 语句中,CONCAT 函数用于将多个字符串拼接在一起,相当于 + 号的功能。在上面的 SQL 语句中,CONCAT 函数接收了两个参数,分别为 'a' 和 'b',最终会将它们拼接成 'ab',最终的 SQL 语句等价于:
SELECT * FROM users WHERE name = 'ab';
三、使用 || 运算符进行拼接
SELECT * FROM users WHERE name = 'a' || 'b';
在 SQL 语句中,|| 运算符用于将两个字符串拼接在一起,它的作用与 + 号和 CONCAT 函数类似。在上面的 SQL 语句中,两个字符串 'a' 和 'b' 会被拼接在一起,最终的 SQL 语句等价于:
SELECT * FROM users WHERE name = 'ab'; 复制代码
四、使用 $ 符号
在 MyBatis 中,拼接字符串还可以使用 $ 符号。例如:
SELECT * FROM users WHERE name = $name;
在 SQL 语句中, 符号用于指定一个字符串拼接,它会在 SQL 语句被执行前进行拼接。与 # 符号不同, 符号不会对输入值进行任何检查和转义,因此它可能会导致 SQL 注入攻击。在上面的 SQL 语句中,name将被拼接到sql语句中,如果name将被拼接到SQL语句中,如果name 的值为 'ab',则最终的 SQL 语句为:
SELECT * FROM users WHERE name = 'ab';
五、# 和 $ 符号
# 用于指定一个占位符,它会在 SQL 语句被执行前进行替换。在下面的 SQL 语句中,#{id} 将被替换为实际的 id 值:
SELECT * FROM users WHERE id = #{id};
如果 #{id} 的值为 1,则最终的 SQL 语句为:
SELECT * FROM users WHERE id = 1;
$ 符号
符号用于指定一个字符串拼接,它会在 SQL 语句被执行前进行拼接。与 # 符号不同, 符号不会对输入值进行任何检查和转义,因此它可能会导致 SQL 注入攻击。例如,在下面的 SQL 语句中,$id 将被拼接到 SQL 语句中:
SELECT * FROM users WHERE id = ${id}; 复制代码
同样如果 $id 的值为 1,则最终的 SQL 语句为
SELECT * FROM users WHERE id = 1; 复
咋一看两者是一样的,那为什么推荐使用 # 符号呢?
区别 —— sql注入风险
Java
String sql = "SELECT * FROM users WHERE name = #{name}"; Map<String, Object> params = new HashMap<>(); params.put("name", "a' or '1' = '1"); // 执行 SQL 语句 SqlSession sqlSession = sqlSessionFactory.openSession(); List<User> users = sqlSession.selectList(sql, params); 复制代码
在执行上面的代码时,MyBatis 会将 #{name} 替换为参数映射中的值,最终的 SQL 语句为:
SQL
SELECT * FROM users WHERE name = 'a\' or \'1\' = \'1'; 复制代码
由于 # 符号会将参数值转义,因此它可以有效防止 SQL 注入攻击。
而 符号仅用于指定一个字符串拼接,它会在 SQL 语句被执行前进行拼接。与 # 符号不同, 符号不会对输入值进行任何检查和转义,因此它可能会导致 SQL 注入攻击。
Java
// 使用 $ 符号拼接字符串 String sql = "SELECT * FROM users WHERE name = ${name}"; Map<String, Object> params = new HashMap<>(); params.put("name", "a' or '1' = '1"); // 执行 SQL 语句 SqlSession sqlSession = sqlSessionFactory.openSession(); List<User> users = sqlSession.selectList(sql, params); 复制代码
例如,在同样的 SQL 语句中,name将被拼接到sql语句中,如果name将被拼接到SQL语句中,如果{name} 的值为 "a' or '1' = '1",则最终的 SQL 语句为:
SQL
SELECT * FROM users WHERE name = a' or '1' = '1; 复制代码
我们可以看到,拼接后没有带上引号;并且没有对 {name} 的值 "a' or '1' = '1" 进行转义。这可能恶意的sql注入发生。因此,建议使用 # 符号来指定占位符,而不是 符号来拼接字符串。