springboot项目中切数据库(mysql-> pg)带来的适配问题:typeHandler

发布于:2024-06-20 ⋅ 阅读:(141) ⋅ 点赞:(0)

一、数据表中有一张表,名为role_permission,DDL如下:

CREATE TABLE "public"."role_permission" (
  "role_id" varchar(64) COLLATE "pg_catalog"."default" NOT NULL,
  "permissions" json,
  "create_time" timestamp(6) DEFAULT CURRENT_TIMESTAMP,
  "update_time" timestamp(6) DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT "role_permission_pkey" PRIMARY KEY ("role_id")
);

ALTER TABLE "public"."role_permission"  OWNER TO "postgres";
这里可以看到是用的pg数据库;

二、定义entity中的数据表对象;

@TableName(value = "role_permission", autoResultMap = true)
public class RolePermission implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    @TableId(value = "role_id", type = IdType.ASSIGN_UUID)
    private String roleId;

    @TableField(value = "permissions", typeHandler = CeGrantedAuthorityListTypeHandler.class)
    private List<CeGrantedAuthority> permissions;
}
这里省略了创建时间和修改时间字段等,重点是要讨论permissions字段;

三、service层中保存数据;

List<CeGrantedAuthority> permissions = authorities.values().stream().flatMap(Collection::stream).collect(Collectors.toList());
     RolePermission rolePermission = new RolePermission()
                .setRoleId(roleId)
                .setPermissions(permissions);
     this.saveOrUpdate(rolePermission);
以上写法,在mysql数据库中可以正常写入,但是在pg数据库是不行的,会报错,其实是pg数据库对json字段类型会进行强校验,所有只有自己复写saveOrUpdate方法;

四、mapper中定义接口及xml实现;

public interface RolePermissionMapper extends BaseMapper<RolePermission> {
    boolean saveOrUpdate(RolePermission rolePermission);
}

重点是以下的xml实现,重点关注红色部分吧,我调了好久,才成功:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.fit2cloud.dao.mapper.RolePermissionMapper">
        <insert id="saveOrUpdate" parameterType="com.fit2cloud.base.entity.RolePermission">
            INSERT INTO "role_permission" (role_id, permissions)
            VALUES (#{roleId,jdbcType=VARCHAR}, to_json(#{permissions, jdbcType=VARCHAR, typeHandler=com.fit2cloud.common.utils.CeGrantedAuthorityListTypeHandler}))
            ON CONFLICT (role_id)
                DO UPDATE SET
                   permissions =  to_json(EXCLUDED.permissions);
        </insert>
</mapper>

五、修改service中的调用

注释掉this.saveOrUpdate(rolePermission);
添加如下调用:

baseMapper.saveOrUpdate(rolePermission);

至此解决

环境:springboot3.1.0

        mybatis-plus:3.5.3.1
        postgsql  13.5

六、修改后带来的一些问题

   mysql切pg数据库后,使用to_json会在json字符串前后加上双引号,并对其中的双引号进行转义,因此在回显时需要先处理一下,这部分也就是在CeGrantedAuthorityListTypeHandler进行修改(以下代码中红色部分就是我加的,能起作用,但是感觉不优雅,欢迎给出更好的解决方案)。

@Override
protected Object parse(String json) {
    try {
        if ( json.startsWith("\"") && json.endsWith("\"") ) {
            json = json.substring(1, json.length() - 1);
        }
        json = json.replace("\\\"","\"");
        JavaType javaType = getObjectMapper().getTypeFactory().constructParametricType(List.class, CeGrantedAuthority.class);
        return getObjectMapper().readValue(json, javaType);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

网站公告

今日签到

点亮在社区的每一天
去签到