We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
在上一篇 文章 中已经介绍了 枚举 类型字段的使用,本文接着介绍 JSON 类型字段的使用。
Mysql 5.7 版本 起增加了对 JSON 类型的支持,表现形式类似于加了 JSON 格式校验的 longtext 。有了这个类型我们就可以存储一些非固定的数据结构来灵活应对多变的业务。
拿订单业务举例,一个订单允许购买多件商品,通常会定义两张表,一张 订单表 和一张 订单商品表 ,然后进行关联查询。
如果用了 JSON 类型就只需一张表了:
DROP TABLE IF EXISTS `order`; CREATE TABLE `order` ( id int(11) NOT NULL AUTO_INCREMENT COMMENT '主键', orderNo varchar(40) NOT NULL COMMENT '订单号', status tinyint(1) NOT NULL COMMENT '订单状态', address json NOT NULL COMMENT '收货地址', orderGoods json NOT NULL COMMENT '订单商品', PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
注意: 请结合实际情况设计表结构,此处是为了演示效果。
对应实体类 :
@Data public class Order implements Serializable { /** * 订单号 */ private String orderNo; /** * 订单状态 */ private Status status; /** * 收货地址 */ private Address address; /** * 订单商品 */ private List<OrderGoods> orderGoods; /** * 序列化时显示状态描述 * * @return */ public String getStatusDesc() { return status == null ? null : status.desc(); } }
地址类:
@Data public class Address implements Serializable { /** * 手机 */ private String mobile; /** * 收货人姓名 */ private String receiver; /** * 详细地址 */ private String adr; }
由于使用 Mybatis 作为 ORM 框架,这里使用 Mybatis 提供的 TypeHandler 实现 枚举类型 的 序列化 和 反序列化 。
实现一个自定义的通用的 TypeHandler
/** * JSON 类型-类型转换器 * <p> * 由于 Mybatis 对泛型嵌套做了处理,T 为泛型类型时会被转为 rawType,所以要注意以下两点: * <p> * 1. 不要使用父类的 rawType 属性,使用本类的 type 属性来做类型转换 * 2. 需要做类型转换的字段要指定 TypeHandler,而不能由 Mybatis 自动查找 * * @author anyesu * @see org.apache.ibatis.type.TypeReference#getSuperclassTypeParameter */ @Slf4j public class JsonTypeHandler<T> extends BaseTypeHandler<T> { private final Type type; /** * 只能由子类调用 */ protected JsonTypeHandler() { type = GenericsUtils.getSuperClassGenericType(getClass()); } /** * 由 Mybatis 根据类型动态生成实例 * * @param type * @see org.apache.ibatis.type.TypeHandlerRegistry#getInstance(Class, Class) */ public JsonTypeHandler(Class<T> rawClass) { this.type = rawClass; } @Override public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, this.toJson(parameter)); } @Override public T getNullableResult(ResultSet rs, String columnName) throws SQLException { return this.toObject(rs.getString(columnName)); } @Override public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return this.toObject(rs.getString(columnIndex)); } @Override public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return this.toObject(cs.getString(columnIndex)); } /** * 序列化 * * @param object * @return */ private String toJson(T object) { return JSON.toJSONString(object); } /** * 反序列化 * * @param content * @return */ private T toObject(String content) { T object = null; if (content != null && content.length() > 0) { try { object = JSON.parseObject(content, getType()); } catch (Exception e) { log.error("", e); } } return object; } public Type getType() { return type; } }
注册 JsonTypeHandler
@Configuration public class MybatisTypeHandlerConfiguration { /** * 注册 Mybatis 类型转换器 */ @Autowired public void registerTypeHandlers() { jsonTypes().forEach(this::registerJsonTypeHandler); } /** * 注册 JSON 类型的类型转换器 * * @param javaTypeClass Java 类型 */ private void registerJsonTypeHandler(Class<?> javaTypeClass) { register(javaTypeClass, JsonTypeHandler.class); } /** * 注册类型转换器 * * @param javaTypeClass Java 类型 * @param typeHandlerClass 类型转换器类型 */ private void register(Class<?> javaTypeClass, Class<?> typeHandlerClass) { this.typeHandlerRegistry.register(javaTypeClass, typeHandlerClass); } /** * 简单 JSON 类型 * * @return */ private List<Class<?>> jsonTypes() { // TODO 这里为了方便就硬编码记录类型,自行替换扫描的方式 return Arrays.asList(Address.class); } }
上面的方式只是注册了 Address 类的类型转换器,对于 List 这种 泛型类型 则无法使用这种方式注册,需要使用下面的方法:
实现 JsonTypeHandler 的子类
public class OrderGoodsListTypeHandler extends JsonTypeHandler<List<OrderGoods>> { }
然后修改 application.yml 让 Mybatis 去扫描注册自定义的 TypeHandler :
mybatis: type-handlers-package: com.github.anyesu.common.typehandler
然后在 Mapper 中显式指定 typeHandler
<update id="updateByPrimaryKey"> update `order` set orderNo = #{orderNo}, status = #{status}, address = #{address}, orderGoods = #{orderGoods, typeHandler=com.github.anyesu.common.typehandler.OrderGoodsListTypeHandler} where id = #{id} </update>
注意: 如果 orderGoods 字段不指定 typeHandler 会被识别为 Object 类型并使用 ObjectTypeHandler 来转换,因此会导致错误。
另外,如果使用了 set 标签,orderGoods 能被为 List 类型,而 OrderGoodsListTypeHandler 被注册为 List 类型的类型转换器,所以能正常执行。( 最好还是显式指定 typeHandler )
<update id="updateByPrimaryKeySelective"> update `order` <set> <if test="orderNo != null"> orderNo = #{orderNo}, </if> <if test="status != null"> status = #{status}, </if> <if test="address != null"> address = #{address}, </if> <!-- 包裹在 set 标签内被正确识别为 List 类型 --> <!-- 最好还是显式指定类型转换器 --> <if test="orderGoods != null"> orderGoods = #{orderGoods} </if> </set> where id = #{id} </update>
篇幅有限,上面代码并不完整,点击 这里 查看完整代码。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
前言
在上一篇 文章 中已经介绍了 枚举 类型字段的使用,本文接着介绍 JSON 类型字段的使用。
关于 JSON 类型 ( 参考 )
Mysql 5.7 版本 起增加了对 JSON 类型的支持,表现形式类似于加了 JSON 格式校验的 longtext 。有了这个类型我们就可以存储一些非固定的数据结构来灵活应对多变的业务。
使用
拿订单业务举例,一个订单允许购买多件商品,通常会定义两张表,一张 订单表 和一张 订单商品表 ,然后进行关联查询。
如果用了 JSON 类型就只需一张表了:
注意: 请结合实际情况设计表结构,此处是为了演示效果。
对应实体类 :
地址类:
DAO 层处理
由于使用 Mybatis 作为 ORM 框架,这里使用 Mybatis 提供的 TypeHandler 实现 枚举类型 的 序列化 和 反序列化 。
实现一个自定义的通用的 TypeHandler
注册 JsonTypeHandler
上面的方式只是注册了 Address 类的类型转换器,对于 List 这种 泛型类型 则无法使用这种方式注册,需要使用下面的方法:
实现 JsonTypeHandler 的子类
然后修改 application.yml 让 Mybatis 去扫描注册自定义的 TypeHandler :
然后在 Mapper 中显式指定 typeHandler
注意: 如果 orderGoods 字段不指定 typeHandler 会被识别为 Object 类型并使用 ObjectTypeHandler 来转换,因此会导致错误。
另外,如果使用了 set 标签,orderGoods 能被为 List 类型,而 OrderGoodsListTypeHandler 被注册为 List 类型的类型转换器,所以能正常执行。( 最好还是显式指定 typeHandler )
源码
篇幅有限,上面代码并不完整,点击 这里 查看完整代码。
转载请注明出处:https://www.jianshu.com/p/7d24167ccf6d
The text was updated successfully, but these errors were encountered: