在springboot项目开发中,一般使用关系型数据库作为主库存储数据,有时候业务场景需要在既有的表结构上,扩展自定义业务信息. 这种场景下一般使用json类型存储。本文总结springboot项目中,借助mybatis-plus操作json实践方案
JSON类型相对于传统的关系型结构,其具有数据本身对结构描述、动态扩展和嵌套等特性,能够更加自由地表示和存储数据
json字段的存储依赖于底层选择的数据库, 有的关系型数据库已经支持json,比如MySQL5.7版本中,引入了JSON类型。如果没有特殊的json类型, 我们可以使用text类型存储json文本。因此要分两种情况分析. 这两种模式区别:
无论底层数据库使用text类型还是json类型。持久层使用mybatis-plus都要处理json与对象的映射问题。创建一个Account账号对象为例,增加一个extendJson作为存储扩展数据的json对象
@TableName(value = "account", autoResultMap = true) public class Account { @TableId(type = IdType.AUTO) private Long id; private String name; private String username; /** * 注意!! 必须开启映射注解 * * @TableName(autoResultMap = true) ** 以下两种类型处理器,二选一 也可以同时存在 *
* 注意!!选择对应的 JSON 处理器也必须存在对应 JSON 解析依赖包 */ //@TableField(typeHandler = JacksonTypeHandler.class) @TableField(typeHandler = FastjsonTypeHandler.class) private JSONObject extendJson; //setter/getter忽略
以上部分主要参考mp官网:https://baomidou.com/ >>字段类型处理器
使用text字段测试json字段我们使用h2数据库进行测试
使用liquibase管理建表语句
text存储json的数据操作与查询与普通text操作无差别
@Service public class AccountServiceImpl implements AccountService { @Autowired private AccountMapper accountMapper; public void createAccount(Account account) { account.setUsername(UUID.randomUUID().toString().replace("-", "")); this.accountMapper.insert(account); } public Account updateAccount(Account account) { this.accountMapper.updateById(account); return this.accountMapper.selectById(account.getId()); } @Override public ListlistAll() { return this.accountMapper.selectList(Wrappers.emptyWrapper()); } }
效果:
使用liquibase管理建表语句
mysql支持json类型因此借助特定的语法可以实现json精确查询及模糊查询
@Service public class AccountServiceImpl implements AccountService { @Autowired private AccountMapper accountMapper; public void createAccount(Account account) { account.setUsername(UUID.randomUUID().toString().replace("-", "")); this.accountMapper.insert(account); } public Account updateAccount(Account account) { this.accountMapper.updateById(account); return this.accountMapper.selectById(account.getId()); } /** * json 数据模糊查询 * @param key extend_json 中的json的key * @param value extend_json 中的json的key对应value * @return */ public ListlistByJsonLike(String key, String value) { // QueryChainWrapper queryWrapper = new QueryChainWrapper<>(this.accountMapper); LambdaQueryWrapper queryWrapper = Wrappers. lambdaQuery(); //json字段模式查询 queryWrapper.apply("JSON_EXTRACT(extend_json, '$." + key + "') LIKE {0}", "%" + value + "%") .ge(Account::getId, 10000); return this.accountMapper.selectList(queryWrapper); } /** * json 数据精确查询 * @param key extend_json 中的json的key * @param value extend_json 中的json的key对应value * @return */ public List listByJsonEquals(String key, String value) { LambdaQueryWrapper queryWrapper = Wrappers. lambdaQuery(); //json字段精确查询 queryWrapper.apply("JSON_EXTRACT(extend_json, '$." + key + "') = {0}", value); return this.accountMapper.selectList(queryWrapper); } @Override public List listAll() { return this.accountMapper.selectList(Wrappers.emptyWrapper()); } }
TODO MySQLJSON索引用法介绍
public class YourService { @Autowired private YourMapper yourMapper; public YourEntity getByJsonKey(String key, String value) { QueryWrapperqueryWrapper = Wrappers. lambdaQuery() .apply("json_data->'$.key' = {0}", value); return yourMapper.selectOne(queryWrapper); } }
在上述示例中,.apply(“json_data->‘$.key’ = {0}”, value) 中的 {0} 将会被 MyBatis-Plus 自动处理为预编译参数,保证了 SQL 的安全性。
请确保你的 MyBatis-Plus 版本支持 .apply() 方法,该方法可以用于执行自定义的 SQL 查询条件。