MyBatis 传入 JSON 如何取键值:从参数解析到灵活取值
在 MyBatis 开发中,我们经常会遇到需要传入 JSON 字符串并在 SQL 语句中解析其中键值对的情况,这种场景在动态查询、多条件筛选等需求中尤为常见,本文将详细介绍如何在 MyBatis 中高效处理传入的 JSON 参数,并从中灵活提取所需的键值。
MyBatis 接收 JSON 参数的方式
MyBatis 本身并不直接支持 JSON 类型的参数,但我们可以通过以下几种方式传入 JSON 字符串并解析其键值:
使用 @Param 注解传入 JSON 字符串
List<User> selectUsersByJson(@Param("params") String jsonParams);
使用 Map 接收 JSON 解析后的对象
List<User> selectUsersByMap(Map<String, Object> paramMap);
使用自定义对象接收 JSON(需 JSON 解析库支持)
List<User> selectUsersByObject(@Param("query") UserQuery query);
在 XML 映射文件中解析 JSON 键值
使用 MyBatis 的 OGNL 表达式(有限支持)
MyBatis 的 OGNL 表达式对 JSON 的支持有限,基本无法直接解析 JSON,我们需要借助数据库的 JSON 函数或预处理方式。
使用数据库原生 JSON 函数
MySQL 示例:
<select id="selectUsersByJson" resultType="User">
SELECT * FROM user
WHERE
<if test="params != null">
JSON_UNQUOTE(JSON_EXTRACT(#{params}, '$.name')) = #{params.name}
AND JSON_UNQUOTE(JSON_EXTRACT(#{params}, '$.age')) = #{params.age}
</if>
</select>
PostgreSQL 示例:
<select id="selectUsersByJson" resultType="User">
SELECT * FROM user
WHERE
<if test="params != null">
params->>'name' = #{params.name}
AND params->>'age' = #{params.age}
</if>
</select>
预处理 JSON 为 Map 对象(推荐)
在 Service 层先将 JSON 字符串解析为 Map,再传入 MyBatis:
// Service 层
String jsonParams = "{\"name\":\"John\", \"age\":30}";
Map<String, Object> paramMap = new ObjectMapper().readValue(jsonParams, new TypeReference<Map<String, Object>>() {});
List<User> users = userMapper.selectUsersByMap(paramMap);
<!-- Mapper XML -->
<select id="selectUsersByMap" resultType="User">
SELECT * FROM user
WHERE
<if test="name != null">
name = #{name}
</if>
<if test="age != null">
AND age = #{age}
</if>
</select>
高级技巧:自定义 TypeHandler 处理 JSON
如果需要频繁处理 JSON 参数,可以自定义 TypeHandler:
@MappedTypes(Map.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class JsonTypeHandler implements TypeHandler<Map<String, Object>> {
private final ObjectMapper objectMapper = new ObjectMapper();
@Override
public Map<String, Object> getResult(ResultSet rs, String columnName) throws SQLException {
String json = rs.getString(columnName);
return parseJson(json);
}
@Override
public Map<String, Object> getResult(CallableStatement cs, int columnIndex) throws SQLException {
String json = cs.getString(columnIndex);
return parseJson(json);
}
private Map<String, Object> parseJson(String json) {
try {
return objectMapper.readValue(json, new TypeReference<Map<String, Object>>() {});
} catch (Exception e) {
throw new RuntimeException("Failed to parse JSON", e);
}
}
// 其他必要方法...
}
然后在 Mapper 接口中使用:
@Select("SELECT * FROM user WHERE json_column = #{jsonParam,jdbcType=VARCHAR,typeHandler=com.example.JsonTypeHandler}")
List<User> selectUsersByJsonTypeHandler(@Param("jsonParam") String jsonParam);
最佳实践建议
-
优先选择预处理方式:在 Service 层将 JSON 解析为 Map 或对象,再传入 MyBatis,避免在 SQL 中直接解析 JSON。
-
利用数据库 JSON 功能:对于现代数据库(如 MySQL 5.7+、PostgreSQL、SQL Server 2016+),优先使用数据库原生的 JSON 函数。
-
性能考虑:JSON 解析有一定性能开销,对于高频操作,考虑直接使用对象而非 JSON 字符串。
-
安全性:确保传入的 JSON 参数可信,避免 JSON 注入风险。
-
类型安全:尽可能使用强类型的 Java 对象而非 Map,以获得更好的类型检查和 IDE 支持。
MyBatis 传入 JSON 并取键值的需求可以通过多种方式实现,从简单的字符串处理到复杂的自定义 TypeHandler,选择哪种方式取决于具体的应用场景、数据库版本和性能要求,对于大多数应用场景,推荐在 Service 层进行 JSON 解析,然后将结构化数据传入 MyBatis,这样既能保持 SQL 的简洁性,又能获得良好的类型安全和性能表现。
随着 JSON 在数据交换中的普及, MyBatis 中处理 JSON 的技巧将大大提升我们应对复杂业务需求的能力,希望本文介绍的方法能帮助你在实际开发中更加灵活地处理 JSON 参数。



还没有评论,来说两句吧...