首页 > 数据库 >JPA实体类映射PostgreSQL中的jsonb字段

JPA实体类映射PostgreSQL中的jsonb字段

时间:2023-08-01 21:55:55浏览次数:38  
标签:实体类 return jsonb Object class Override PostgreSQL public

前言

有时候我们需要在PostgreSQL表中存储jsonb类型的数据,JPA实体类中如何定义这个属性与之对应呢?

本篇介绍两种方式:

① 自定义数据库方言和自定义类型

② 引入hibernate-types依赖

方式一

自定义数据库方言和自定义类型

  1. 自定义方言

    public class CustomPostgreSqlDialect extends PostgreSQL9Dialect {
        public CustomPostgreSqlDialect() {
            super();
            this.registerColumnType(Types.JAVA_OBJECT, "jsonb");
        }
    }
    
  2. 自定义类型

    public class JsonbType implements UserType {
    
        private static final XxxLogger LOGGER = XxxLoggerFactory.getLogger(JsonbType.class);
    
        private final ObjectMapper mapper = new ObjectMapper();
    
        @Override
        public int[] sqlTypes() {
            return new int[]{Types.JAVA_OBJECT};
        }
    
        @Override
        public Class<?> returnedClass() {
            return Map.class;
        }
    
        @Override
        public boolean equals(Object x, Object y) throws HibernateException {
            return ObjectUtils.nullSafeEquals(x, y);
        }
    
        @Override
        public int hashCode(Object x) throws HibernateException {
            return x == null ? 0 : x.hashCode();
        }
    
        @Override
        public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor sharedSessionContractImplementor, Object owner) throws HibernateException, SQLException {
            Object obj = rs.getObject(names[0]);
            if (obj == null) {
                return null;
            }
            PGobject o = (PGobject) obj;
            if (o.getValue() != null) {
                try {
                    // return JSON.parse(o.getValue(), Map.class);
                    return mapper.readValue(o.getValue(), Map.class);
                } catch (IOException e) {
                    LOGGER.error();
                }
            }
            return new HashMap<String, Object>();
        }
    
        @Override
        public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor sharedSessionContractImplementor) throws HibernateException, SQLException {
            if (value == null) {
                st.setNull(index, Types.OTHER);
            } else {
                try {
                    // st.setObject(index, JSON.toJSON(value), Types.OTHER);
                    st.setObject(index, mapper.writeValueAsString(value), Types.OTHER);
                } catch (IOException e) {
                    LOGGER.error();
                }
            }
        }
    
        @Override
        public Object deepCopy(Object originalValue) throws HibernateException {
            if (originalValue != null) {
                try {
                    // 替换为其他JSON解析器
                    // return JSON.parse(JSON.toJSON(originalValue), returnedClass());
                    return mapper.readValue(mapper.writeValueAsString(originalValue), returnedClass());
                } catch (IOException e) {
                    LOGGER.error();
                    throw new HibernateException("Failed to deep copy object", e);
                }
            }
            return null;
        }
    
        @Override
        public boolean isMutable() {
            return true;
        }
    
        @Override
        public Serializable disassemble(Object value) throws HibernateException {
            Object copy = deepCopy(value);
    
            if (copy instanceof Serializable) {
                return (Serializable) copy;
            }
            throw new SerializationException(String.format("Cannot serialize '%s', %s is not Serializable.", value, value.getClass()), null);
        }
    
    
        @Override
        public Object assemble(Serializable cached, Object o) throws HibernateException {
            return deepCopy(cached);
        }
    
        @Override
        public Object replace(Object original, Object target, Object owner) throws HibernateException {
            return deepCopy(original);
        }
    
    }
    
  3. 自定义方言在application.properties中声明

    # CustomPostgreSqlDialect的全限定名
    spring.jpa.database-platform=com.xx.CustomPostgreSqlDialect
    
  4. 实体中的字段

    @Data
    @Entity
    @Table(name = "test_jsonb_entity")
    @TypeDef(name = "JsonbType", typeClass = JsonbType.class) // 自定义类型
    public class TestJsonbEntity {
    
    	// 主键...
        private Integer id;
        
        /**
         * jsonb类型的字段
         */
        @Column(columnDefinition = "jsonb")
        @Type(type = "JsonbType") // @TypeDef中的name
        private Map<String, Object> clusterInfo;
        
    }
    

方式二

引入hibernate-types依赖

  1. maven坐标

    <dependency>
        <groupId>com.vladmihalcea</groupId>
        <artifactId>hibernate-types-52</artifactId>
        <version>2.3.4</version>
    </dependency>
    
  2. 实体类

    @Data
    @Entity
    @Table(name = "test_jsonb_entity")
    @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class) // hibernate-types 包下的JsonBinaryType
    public class TestJsonbEntity implements Serializable {
        
        // 主键...
        private Integer id;
        
        @Column(columnDefinition = "jsonb", name = "cluster_info")
        @Type(type = "jsonb") // @TypeDef中的name
        private ClusterInfo clusterInfo; // ClusterInfo类根据自己需要定义
        
    }
    

查询

可以使用JPA的原生sql查询,参考:JSON 函数和操作符

标签:实体类,return,jsonb,Object,class,Override,PostgreSQL,public
From: https://www.cnblogs.com/charlton/p/17599200.html

相关文章

  • PostgreSQL-PITR 增量备份与恢复
    Point-in-TimeRecovery(PITR)基于时间点的备份(恢复)。归档对于PITR(增量备份与恢复)至关重要,如果归档不一致,会产生各种各样的问题。以下的测试截图中,我将归档清零,重新生成,再做相关PITR的操作。这里是简单的操作过程,详情查看相关的官方文档说明 26.3.ContinuousArchivingandPoi......
  • PostgreSQL-由于与数据库的某些自动连接而无法删除数据库
    PostgreSQL常见问题解决1.删除databaseDROPDATABASEviid; 执行上述sql报错信息如下:ERROR:database"viid"isbeingaccessedbyotherusersDETAIL:Thereis1othersessionusingthedatabase. 原因是有其他的session正在使用该数据库 解决方法:强......
  • PostgreSQL的使用
    显示所有用户和角色的权限\du显示所有表的权限\dp切换到myDatabase数据库\cmyDatabase使用username登录myDatabase数据库psql-Uusername-dmyDatabase;移除username在myDatabase数据库上的所有权限revokeallprivilegesondatabasemyDatabasefromusername;移除......
  • postgresql | sql语句表名和列名引号问题
    根据您提供的SQL查询语句:SELECT*FROM"features"WHERE"layer"="FSHFAC"LIMIT10;在语法上看起来没有问题,但在实际运行时可能会出现一些问题,这取决于数据库和数据表的结构。表名和列名引号:在SQL中,使用双引号""可以将标识符(例如表名、列名等)加以引号。但是,要确保......
  • postgresql的相关利用
    有比较多的安全设备或者web系统使用postgresql作为数据库,研究postgresql数据库如何getshell将有很大帮助外联postgresql默认本地连接(5432端口),远程连接需要找到postgres安装目录下的/data/pg_hba.conf,在IPv4配置处加上:hostallall192.168.0.1/24scram-sha-256之后重启post......
  • Postgresql 在Ubuntuserver 22.04上部署
    安装与卸载系统环境:1.ubuntu22.04server安装1.检查是否已经安装#psql服务sudoservicepostgresqlstatus#版本查看psql--version2.安装命令#更新安装源内容sudoapt-getupdate#postgresql-contrib额外特性安装sudoaptinstallpostgresqlpostgresql......
  • PostgreSQL中WAL日志解析工具——WalMiner
    WalMiner是从PostgreSQL的WAL(writeaheadlogs)日志中解析出执行的SQL语句的工具,并能生成对应的undoSQL语句。与传统的logicaldecode插件相比,walminer不要求logical日志级别且解析方式较为灵活。WalMiner背景WAL日志在PostgreSQL中,WAL日志记录了数据库重要数据文件的所有变化,你......
  • ruby web 实战(10)-postgresql(1)
    目录user和installuser和install用户建议运行PostgreSQL在单独的用户帐户下。此用户帐户应仅拥有由服务器,不应与其他守护进程共享.特别是,建议该用户帐户不拥有PostgreSQL可执行文件,以确保受损的服务器进程无法修改这些可执行文件。PostgreSQL的预打包版本通常会在软......
  • postgresql 数据库 报错 FATAL: sorry, too many clients already 解决方法
    场景项目postgres连接不上,所有连接报错:psql:FATAL:sorry,toomanyclientsalready原由程序使用连接未及时释放,连接一直处于idle状态处理方式1、程序里面未释放的连接,在使用后及时释放;2、postgres连接数默认最大100个,在配置文件修改该参数;postgres.confmax_con......
  • mysql 代码适配 postgresql 适配改写,优化案例(行转列 + 标量子查询改写)
    最近在适配个MySQL应用的项目,各种SQL改成PG兼容的语法真的是脑壳痛,今天遇到个有意思的案例。原MySQLSQL语句:SELECTDISTINCTl.MALL_NAME'项目',t.CONT_NO'合同编号',t.COMPANY_NAME'租户',t.STORE_NOS'铺位号',(selectGROUP_CONCAT(r.FLOO......