• MyBatis通过TypeHandler自动编解码对象的Json属性


    mysql从5.7.版本开始支持json列。它本质上仍然是一个字符串,比起直接用varchar来说,它有专门对于json的的检索,修改方法。更加的灵活。

    在jdbc规范中,还没json类型的定义。所以对象一般都是用String属性,映射数据库的json列。在存储和读取的时候,需要自己完成json的序列化和反序列化。

    在使用MyBatis的框架,可以通过定义TypeHandler来自动完成Json属性的序列化和反序列化。

    演示一个Demo

    这里使用GsonJsonElement作为对象的Json属性对象。我觉得它比较灵活,可以在JsonObjectJsonArray中随意转换。

    整合MyBatis

    ... 略

    表结构 & 模型对象

    表结构

    CREATE TABLE `website` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
      `name` varchar(255) NOT NULL COMMENT '网站名称',
      `properties` json DEFAULT NULL COMMENT '网站属性,这是一个Json列',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    

    模型对象

    import com.google.gson.JsonElement;
    
    public class WebSite {
    	// 网站id
    	private Integer id;
    	// 网站名称
    	private String name;
    	// 网站属性,json
    	private JsonElement properties;
    	public Integer getId() {
    		return id;
    	}
    	public void setId(Integer id) {
    		this.id = id;
    	}
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public JsonElement getProperties() {
    		return properties;
    	}
    	public void setProperties(JsonElement properties) {
    		this.properties = properties;
    	}
    	@Override
    	public String toString() {
    		return "WebSite [id=" + id + ", name=" + name + ", properties=" + properties + "]";
    	}
    }
    

    自定义 TypeHandler

    
    import java.sql.CallableStatement;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    import org.apache.ibatis.type.BaseTypeHandler;
    import org.apache.ibatis.type.JdbcType;
    
    import com.google.gson.JsonElement;
    import com.google.gson.JsonParser;
    
    public class JsonElementTypeHandler extends BaseTypeHandler<JsonElement> {
    
    	/**
    	 * Json编码,对象 ==> Json字符串
    	 */
    	@Override
    	public void setNonNullParameter(PreparedStatement ps, int i, JsonElement parameter, JdbcType jdbcType) throws SQLException {
    		String value = parameter.toString();
    		if (jdbcType == null) {
    			ps.setObject(i, value);
    		} else {
    			ps.setObject(i, value, jdbcType.TYPE_CODE);
    		}
    	}
    
    	/**
    	 * Json解码,Json字符串 ==> 对象
    	 */
    	@Override
    	public JsonElement getNullableResult(ResultSet rs, String columnName) throws SQLException {
    		String result = rs.getString(columnName);
    		return result == null ? null : JsonParser.parseString(result);
    	}
    
    	/**
    	 * Json解码,Json字符串 ==> 对象
    	 */
    	@Override
    	public JsonElement getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
    		String result = rs.getString(columnIndex);
    		return result == null ? null : JsonParser.parseString(result);
    	}
    
    	/**
    	 * Json解码,Json字符串 ==> 对象
    	 */
    	@Override
    	public JsonElement getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
    		String result = cs.getString(columnIndex);
    		return result == null ? null : JsonParser.parseString(result);
    	}
    }
    
    

    在mybatis配置文件中,配置handler

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
    	PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    	"http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    	<typeHandlers>
    		<typeHandler handler="io.springboot.jpa.mybatis.handler.JsonElementTypeHandler" javaType="com.google.gson.JsonElement"/>
    	</typeHandlers>
    </configuration>
    

    Mapper的定义

    import org.apache.ibatis.annotations.Insert;
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Options;
    import org.apache.ibatis.annotations.Param;
    import org.apache.ibatis.annotations.Select;
    
    import io.springboot.jpa.entity.WebSite;
    
    @Mapper
    public interface WebSiteMapper {
    	
    	@Insert("INSERT INTO `website`(`id`, `name`, `properties`) VALUES(#{id}, #{name}, #{properties});")
    	@Options(useGeneratedKeys = true, keyColumn = "id", keyProperty = "id")
    	int save(WebSite webSite);
    	
    	@Select("SELECT * FROM `website` WHERE `id` = #{id};")
    	WebSite findById(@Param("id") Integer id);
    }
    
    

    测试

    private static final Logger LOGGER = LoggerFactory.getLogger(JpaApplicationTest.class);
    
    @Autowired
    private WebSiteMapper webSiteMapper;
    
    @Test
    @Transactional
    @Rollback(false)
    public void test () {
    	WebSite webSite = new WebSite();
    	webSite.setName("SpringBoot中文社区");
    	
    	// 初始化properties属性
    	JsonObject jsonObject = new JsonObject();
    	jsonObject.addProperty("url", "https://springboot.io");
    	jsonObject.addProperty("initializr", "https://start.springboot.io");
    	jsonObject.addProperty("Github", "https://github.com/springboot-community");
    	
    	webSite.setProperties(jsonObject);
    	
    	// 存储
    	this.webSiteMapper.save(webSite);
    	
    	// 根据id检索
    	webSite = this.webSiteMapper.findById(webSite.getId());
    	
    	LOGGER.info("resut={}", new Gson().toJson(webSite));
    }
    

    日志输出

    org.mybatis.spring.SqlSessionUtils       : Creating a new SqlSession
    org.mybatis.spring.SqlSessionUtils       : Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@34be7efb]
    o.m.s.t.SpringManagedTransaction         : JDBC Connection [HikariProxyConnection@885723920 wrapping com.mysql.cj.jdbc.ConnectionImpl@625487a6] will be managed by Spring
    i.s.jpa.mapper.WebSiteMapper.save        : ==>  Preparing: INSERT INTO `website`(`id`, `name`, `properties`) VALUES(?, ?, ?);
    i.s.jpa.mapper.WebSiteMapper.save        : ==> Parameters: null, SpringBoot中文社区(String), {"url":"https://springboot.io","initializr":"https://start.springboot.io","Github":"https://github.com/springboot-community"}(String)
    i.s.jpa.mapper.WebSiteMapper.save        : <==    Updates: 1
    org.mybatis.spring.SqlSessionUtils       : Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@34be7efb]
    org.mybatis.spring.SqlSessionUtils       : Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@34be7efb] from current transaction
    i.s.jpa.mapper.WebSiteMapper.findById    : ==>  Preparing: SELECT * FROM `website` WHERE `id` = ?;
    i.s.jpa.mapper.WebSiteMapper.findById    : ==> Parameters: 4(Integer)
    i.s.jpa.mapper.WebSiteMapper.findById    : <==      Total: 1
    org.mybatis.spring.SqlSessionUtils       : Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@34be7efb]
    i.s.jpa.test.JpaApplicationTest          : resut={"id":4,"name":"SpringBoot中文社区","properties":{"url":"https://springboot.io","Github":"https://github.com/springboot-community","initializr":"https://start.springboot.io"}}
    

    不论是写入还是读取,都无误的对JsonElement完成了编码和解码。

    核心只要明白了 TypeHandler的几个方法,不管是Gson, Fastjson, Jackson 甚至是自定义对象,都可以很简单的完成自动映射。

    原文:https://springboot.io/t/topic/2455

  • 相关阅读:
    redis同步指定key数据到其他redis中
    Golang 生成随机数
    怎么理解“平均负载”? 进行分析等
    Golang打印空心金字塔for循环实现
    python十几行代码实现三级菜单
    mysql增量恢复
    python内建函数
    python练习题总结
    迭代器和生成器
    python基础数据类型
  • 原文地址:https://www.cnblogs.com/kevinblandy/p/13517633.html
Copyright © 2020-2023  润新知