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