在 MyBatis 中编写 Neo4j 查询时,#{}
和 ${}
的主要区别在于参数替换的方式,这与 MyBatis 操作传统关系型数据库时的规则类似,但在 Neo4j 的 Cypher 查询中有一些特殊注意事项。
必须使用 ${}
而不能用 #{}
的情况:
-
动态标识符(节点标签、关系类型、属性名):
-
当需要动态指定节点标签、关系类型或属性名时,必须使用
${}
,因为这些位置 Cypher 语法不接受参数化。 -
例如:
xmlMATCH (n:${label}) WHERE n.${property} = #{value} RETURN n
这里
label
和property
必须用${}
,而value
可以用#{}
。
-
-
Cypher 关键字或子句动态拼接:
-
如果需要动态拼接 Cypher 的关键字部分(如 ORDER BY、WHERE 条件等),必须使用
${}
。 -
例如:
xmlMATCH (n:Person) ${whereClause} RETURN n
-
-
动态索引或约束名称:
- 创建或使用索引/约束时,名称需要用
${}
。
- 创建或使用索引/约束时,名称需要用
-
Cypher 函数或特殊语法:
- 如果参数需要作为 Cypher 函数名或特殊语法的一部分。
应该使用 #{}
的情况:
- 对于普通的属性值、查询参数等,应该始终优先使用
#{}
,因为:-
它会被预编译为参数化查询,防止 Cypher 注入
-
有类型安全处理
-
例如:
xmlMATCH (n:Person) WHERE n.name = #{name} RETURN n
-
安全注意事项:
- 永远不要用
${}
直接接收用户输入,这会导致 Cypher 注入风险 - 如果必须使用
${}
,应该:- 仅在动态 SQL 的必要部分使用
- 确保值来自可信来源(如系统常量、枚举值等)
- 考虑在应用层做白名单校验
示例对比:
xml
<!-- 安全的方式 -->
<select id="findByLabelAndProperty">
MATCH (n:${label}) WHERE n.${property} = #{value} RETURN n
</select>
<!-- 危险的方式(不要这样用) -->
<select id="findByLabelUnsafe">
MATCH (n:${userInput}) RETURN n <!-- 可能被注入 -->
</select>
总结:在 Neo4j 查询中,只有当需要动态改变 Cypher 查询的结构部分(标签、属性名、关系类型等)时才必须用 ${}
,其他所有值都应该用 #{}
。