PG JSONB 对应 Java 字段 + MyBatis-Plus 完整实战
一、核心对应关系
PostgreSQL 的 jsonb 字段,在 Java 中推荐 3 种对应类型(优先级从高到低):
- 自定义实体类(✅ 最推荐,业务清晰、类型安全)
Map<String, Object>(灵活,无固定 JSON 结构)String(最简单,手动序列化/反序列化)
二、MyBatis-Plus 核心关键
MP 要实现 Java 对象 ↔ PG jsonb 自动转换,必须使用【类型处理器(TypeHandler)】
- MP 自带
JacksonTypeHandler(无需自定义,直接用) - 实体类必须加 2 个关键注解:
@TableName(autoResultMap = true):开启自动映射@TableField(typeHandler = JacksonTypeHandler.class, jdbcType = JdbcType.OTHER):绑定 jsonb 处理器
三、完整实战代码
1. 环境依赖(Maven)
xml
<!-- MyBatis-Plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<!-- PostgreSQL驱动 -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Lombok(简化代码) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
2. 数据库表(沿用之前的 PG 表)
sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(50) NOT NULL,
user_info JSONB -- 核心jsonb字段
);
3. Java 实体类(✅ 最优方案:自定义实体)
(1)嵌套 JSON 实体(对应 jsonb 内部结构)
java
import lombok.Data;
import java.util.List;
/**
* 对应 user_info jsonb 字段的结构
*/
@Data
public class UserInfo {
private Integer age;
private String gender;
// 嵌套对象
private Address address;
// 数组
private List<String> hobbies;
}
// 嵌套地址对象
@Data
class Address {
private String city;
private String code;
}
(2)主实体类(绑定 TypeHandler)
java
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.Data;
import org.apache.ibatis.type.JdbcType;
@Data
// 关键1:开启自动结果映射
@TableName(value = "users", autoResultMap = true)
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String username;
// 关键2:绑定jsonb类型处理器
@TableField(
typeHandler = JacksonTypeHandler.class,
jdbcType = JdbcType.OTHER
)
private UserInfo userInfo; // JSONB → 自定义Java实体
}
4. Mapper 接口(MP 原生接口,无需写 SQL)
java
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper<User> {
// 无需手写增删改查,MP 自动实现
}
四、MyBatis-Plus 增删改查样例
1. 新增(直接传 Java 对象,自动转 jsonb 存库)
java
@Autowired
private UserMapper userMapper;
// 新增用户(jsonb字段自动序列化)
public void addUser() {
// 1. 组装jsonb对象
UserInfo info = new UserInfo();
info.setAge(26);
info.setGender("男");
Address address = new Address();
address.setCity("北京");
address.setCode("100000");
info.setAddress(address);
info.setHobbies(Arrays.asList("篮球", "旅行"));
// 2. 组装主实体
User user = new User();
user.setUsername("zhangsan");
user.setUserInfo(info);
// 3. MP新增(自动把UserInfo转成PG jsonb)
userMapper.insert(user);
}
2. 修改(直接更新 Java 对象,自动覆盖 jsonb)
java
// 修改jsonb字段(例:更新城市、年龄)
public void updateUser() {
// 1. 查询原数据
User user = userMapper.selectById(1L);
// 2. 修改jsonb内部字段
UserInfo info = user.getUserInfo();
info.setAge(27);
info.getAddress().setCity("深圳");
user.setUserInfo(info);
// 3. MP修改(自动转jsonb更新)
userMapper.updateById(user);
}
3. 删除(和普通字段一致,无特殊处理)
java
// 删除(根据id删除,jsonb字段无特殊逻辑)
public void deleteUser() {
userMapper.deleteById(1L);
}
4. 查询(普通查询 + jsonb 嵌套字段条件查询)
(1)普通查询(自动把 jsonb 转回 Java 对象)
java
// 根据id查询,直接拿到UserInfo对象
public void getUser() {
User user = userMapper.selectById(1L);
// 直接使用jsonb数据
System.out.println("年龄:" + user.getUserInfo().getAge());
System.out.println("城市:" + user.getUserInfo().getAddress().getCity());
}
(2)条件查询(查询 jsonb 内部字段,例:男性、年龄>25)
java
// 条件查询:筛选jsonb中gender=男,age>25的用户
public void queryByJsonb() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
// PG原生语法:(user_info->>'age')::int > 25
wrapper.apply("(user_info->>'age')::int > {0}", 25);
wrapper.eq("user_info->>'gender'", "男");
List<User> userList = userMapper.selectList(wrapper);
}
五、备用方案:Map<String, Object> 对应 jsonb
如果 JSON 结构不固定,用 Map 替代自定义实体:
java
@Data
@TableName(value = "users", autoResultMap = true)
public class User {
private Long id;
private String username;
@TableField(
typeHandler = JacksonTypeHandler.class,
jdbcType = JdbcType.OTHER
)
private Map<String, Object> userInfo; // JSONB → Map
}
使用方式:
java
Map<String, Object> info = new HashMap<>();
info.put("age", 26);
info.put("gender", "男");
user.setUserInfo(info);
六、备用方案:String 对应 jsonb
最简单,无自动转换,手动处理:
java
@TableField(jdbcType = JdbcType.OTHER)
private String userInfo; // JSONB → String
使用方式:
java
// 手动传JSON字符串
user.setUserInfo("{\"age\":26,\"gender\":\"男\"}");
七、关键注意事项
- 必须加
autoResultMap = true,否则查询无法把 jsonb 转回 Java 对象 - jdbcType = JdbcType.OTHER:PG jsonb 对应 JDBC 特殊类型
- 优先用自定义实体:业务维护性远高于 Map/String
- 增删改查完全复用 MP 原生方法,无需手写 JSON 相关 SQL
总结
- PG
jsonb→ Java 最优对应:自定义实体类 - MP 核心:
JacksonTypeHandler+autoResultMap = true - 增删改查直接用 MP 原生方法,自动完成对象与 jsonb 的转换
- 条件查询用 PG 原生
->>/->语法配合wrapper.apply()