Mybatis&MybatisPlus 操作 jsonb 格式数据

文章讲述了在MybatisPlus项目中利用PostgreSQL的JSONb类型,配置TypeHandler处理JSON数据,以及在员工数据操作中的具体实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近有用到postgresql,里面的一个特色数据类型便是jsonb,和json差不多,但是查询比较快,关于概念,这里就提一句,不赘述。

我们先来看下用mybatisplus,首先是查询数据。

依赖:

<dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>

然后数据库:

CREATE TABLE employees (
    id SERIAL PRIMARY KEY,
    name TEXT,
    age INTEGER,
    address JSONB
);

INSERT INTO employees (name, age, address) VALUES
  ('Alice', 25, '{"city": "New York", "street": "123 Main St"}'),
  ('Bob', 30, '{"city": "San Francisco", "street": "456 Elm St"}'),
  ('Charlie', 35, '{"city": "Seattle", "street": "789 Oak St"}'),
  ('David', 28, '{"city": "Chicago", "street": "678 Walnut St"}'),
  ('Eve', 27, '{"city": "Los Angeles", "street": "234 Pine St"}'),
  ('Frank', 32, '{"city": "Boston", "street": "345 Maple St"}'),
  ('Grace', 29, '{"city": "Austin", "street": "567 Birch St"}');

前面的都无所谓,主要来看实体类,实体类中有两个地方注意:

因为是用的MP,所以在这里直接就注解上配置了  (这里是为了扩展性,所以才自定义的,其实在MP中,是自带了TypeHandler 的,有Gson,FastJson等等

import com.alibaba.fastjson.JSON;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;
import org.postgresql.util.PGobject;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * @Description:
 * @Author Jack_Lee
 * @Date 2023/9/18 11:30
 */
@MappedTypes(Object.class)
public class JsonTypeHandlerObject<T extends Object> extends BaseTypeHandler<T> {

    private static final PGobject jsonObject = new PGobject();

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
        jsonObject.setType("jsonb");
        jsonObject.setValue(JSON.toJSONString(parameter));
        ps.setObject(i, jsonObject);
    }

    @Override
    public T getNullableResult(ResultSet resultSet, String columnName) throws SQLException {
        return (T) resultSet.getString(columnName);

    }

    @Override
    public T getNullableResult(ResultSet resultSet, int columnIndex) throws SQLException {
        return (T) resultSet.getString(columnIndex);

    }

    @Override
    public T getNullableResult(CallableStatement callableStatement, int columnIndex) throws SQLException {
        return (T) callableStatement.getString(columnIndex);
    }
}

添加TypeHandler,用于类型处理,这个应该不陌生,如有不知道这个的小伙伴,可以去温习一下mybatis相关知识。

定义mapper,这个不用说,最基本的

再来看下Mybatis的,mybatis不像plus,很多都要手动进行配置

先定义一个resultMap,然后在字段上指定TypeHandler即可

<mapper namespace="com.jack.mapper.EmployeesMapper">

    <resultMap id="EmployeesMap" type="com.jack.entity.Employees">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="age" property="age"/>
        <result column="address" property="address" typeHandler="com.jack.handler.JsonTypeHandlerObject"/>
    </resultMap>
    
    <select id="findList"  resultMap="EmployeesMap">
        select * from employees;
    </select>

</mapper>

然后再写个测试类自己测一下,这里不多说

重点说一下插入数据

以mybatis为例,先在mapperx.xml中定义好
 

<insert id="insertEmp" parameterType="com.jack.entity.Employees">
        insert into employees values (#{id}, {name}, {age}, {address,jdbcType=OTHER,typeHandler=com.jack.handler.JsonTypeHandlerObject})
    </insert>
@Mapper
public interface EmployeesMapper {

    int insertEmp();
}

--------------------------------------------------------------------------------------------------------------------------------

补充:如果要存的话,建议还是用Map进行存取,因为刚好也是键值对,比较方便,下面是我自定义的TypeHandler

@MappedTypes(Map.class)
public class JsonTypeHandlerMap<T> extends BaseTypeHandler<T> {

    private static final PGobject pgObject = new PGobject();

    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, T parameter, JdbcType jdbcType) throws SQLException {
        pgObject.setType("jsonb");
        pgObject.setValue(JSON.toJSONString(parameter));
        preparedStatement.setObject(i, pgObject);
    }

    @Override
    public T getNullableResult(ResultSet resultSet, String s) throws SQLException {
        return (T) resultSet.getString(s);
    }

    @Override
    public T getNullableResult(ResultSet resultSet, int i) throws SQLException {
        return (T) resultSet.getString(i);
    }

    @Override
    public T getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        return (T) callableStatement.getString(i);
    }
}

 同样在实体类中指定或者在mapper.xml 中进行指定即可。

然后去测试:

@Test
    public void TestUsersInsert(){
        Users users = new Users();
        users.setId(13);
        users.setName("zhangsan");
        HashMap<String, Object> map = new HashMap<>();
        map.put("name","测试1111");
        map.put("age","测2222");
        System.out.println("---------------------------->>>>     "+ map);
        users.setAddress(map);
        int insert = usersMapper.insert(users);
        System.out.println(insert > 0 ? "成功" : "失败");
    }

 成功存到数据库中

-----------------------------------------------------补充完毕--------------------------------------------------------------

测试用例自己写一下,写的比较潦草,因为是临时记录,又是在公司。

如果有任何问题,请在下方留言,或者直接私信我,我看到都会回复!

### 向数据库表中添加 JSON 字段并使用 MyBatis Plus 映射 当需要在 PostgreSQL 数据库中添加 JSON 类型字段并与 MyBatis Plus 配合工作时,需遵循几个重要步骤来确保操作顺利进行。这不仅涉及 SQL 层面的操作,还包括 Java 实体类以及框架配置方面的调整。 #### 修改数据库表结构以支持 JSON 字段 对于 PostgreSQL 来说,可以利用 `json` 或者更高效的 `jsonb` 类型来存储非结构化的数据[^2]。下面是一个简单的例子展示如何通过 SQL 增加一个名为 `extra_info` 的 jsonb 列: ```sql ALTER TABLE t_demo ADD COLUMN extra_info jsonb; ``` 此命令会向现有表格 `t_demo` 中增加一个新的列用于保存 JSON 对象形式的数据,并允许后续对该列执行复杂的查询和索引优化。 #### 更新实体类定义 为了让 MyBatis Plus 正确识别新增加的 JSON 字段,在对应的 Java 实体类里也需要做出相应更改。假设有一个叫作 `TDemo.java` 的文件,则应像这样扩展它: ```java import com.baomidou.mybatisplus.annotation.TableField; public class TDemo { private Long id; // 新增属性对应于数据库中的 extra_info 列 @TableField(value="extra_info", typeHandler=JsonTypeHandler.class) private Map<String, Object> extraInfo; // Getter 和 Setter 方法... } ``` 这里特别注意的是应用了 `@TableField` 注解指定了自定义类型处理器 `JsonTypeHandler`,这是为了使 MyBatis 能够自动处理从 JSON 格式的字符串到 Java 对象之间的转换过程[^1]。 #### 自定义 Jackson Type Handler 由于默认情况下 MyBatis 并不直接支持将复杂对象序列化成 JSON 存储至数据库,因此还需要编写自己的 `TypeHandler` 来完成这项任务。可以通过继承 `com.fasterxml.jackson.databind.ObjectMapper` 及实现 `org.apache.ibatis.type.TypeHandler` 接口达成目的: ```java import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.Map; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; public class JsonTypeHandler extends BaseTypeHandler<Map<String,Object>> { private static final ObjectMapper objectMapper = new ObjectMapper(); @Override public void setNonNullParameter(PreparedStatement ps, int i, Map<String,Object> parameter, JdbcType jdbcType) throws SQLException { try { String jsonString = objectMapper.writeValueAsString(parameter); ps.setString(i, jsonString); } catch (JsonProcessingException e) { throw new RuntimeException(e.getMessage()); } } @Override public Map<String,Object> getNullableResult(ResultSet rs, String columnName) throws SQLException { String jsonString = rs.getString(columnName); if(jsonString != null && !jsonString.isEmpty()){ try{ return objectMapper.readValue(jsonString, Map.class); }catch(JsonProcessingException ex){ throw new RuntimeException(ex.getMessage()); } } return null; } @Override public Map<String,Object> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { String jsonString = cs.getString(columnIndex); if(jsonString != null && !jsonString.isEmpty()){ try{ return objectMapper.readValue(jsonString, Map.class); }catch(JsonProcessingException ex){ throw new RuntimeException(ex.getMessage()); } } return null; } } ``` 这段代码实现了对 `Map<String, Object>` 类型的支持,使得应用程序能够方便地读取/写入任意键值对组合而成的信息片段作为单个单元存放在关系型数据库内的一行记录之中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值