乐趣区

关于hibernate:jpa之hibernate和jackson踩坑记录

在做的我的项目采纳的是 spring jpa,底层默认应用的是 orm 是 hibernate,通过 hibernate 查问进去的实体对象实际上都是代理对象,在序列化的时候,咱们可能会遇到懒加载导致 jackson 无奈正确解析对象的问题,这个能够通过导入 maven 包

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-hibernate5</artifactId>
</dependency>

而后加载进 objectMapper 上下文

@Bean
public Jackson2ObjectMapperBuilderCustomizer builderCustomizer() {
    return builder -> {
        //jackson 序列化 和 hibernate 懒加载
        builder.modulesToInstall(hibernate5Module());
    };
}

private static Hibernate5Module hibernate5Module() {Hibernate5Module hibernate5Module = new Hibernate5Module();
    hibernate5Module.configure(REPLACE_PERSISTENT_COLLECTIONS, true);
    //hibernate5Module.configure(FORCE_LAZY_LOADING, true);
    return hibernate5Module;
}

这样在序列化的时候就会判断之前是否存在数据了,如果是懒加载则会序列化为 null。


我在反序列化的时候会报 failed to lazily initialize a collection, could not initialize proxy…,起初看了一下序列化后的 json,发现有些提早加载的 Collection 类型的会解析成 org.hibernate.collection.internal.PersistentBag(hibernate 的代理对象),而不是咱们个别 json 的汇合模式。导致反序列化的时候,会生成 PersistentBag 对象,这时候 jackson 操作 PersistentBag,会导致 hibernate 检测到数据变动,从而触发它的一些操作而报下面的错。

而后我就排查,为啥序列化的时候会转成 PersistentBag 对象呢?能够看看 Hibernate5Module 里的代码,该模块会加载两个

context.addSerializers(new HibernateSerializers(_mapping, _moduleFeatures));
context.addBeanSerializerModifier(new HibernateSerializerModifier(_moduleFeatures, _sessionFactory));

// 序列化处理器,咱们之前的解决懒加载原理也是通过这两个解决的,而后我在
HibernateSerializerModifier 里看到了 PersistentCollectionSerializer,对于汇合类型的解析解决,其中次要有个判断办法
protected boolean usesLazyLoading(BeanProperty property) {if (property != null) {// As per [Issue#36]
        ElementCollection ec = property.getAnnotation(ElementCollection.class);
        if (ec != null) {return (ec.fetch() == FetchType.LAZY);
        }
        OneToMany ann1 = property.getAnnotation(OneToMany.class);
        if (ann1 != null) {return (ann1.fetch() == FetchType.LAZY);
        }
        OneToOne ann2 = property.getAnnotation(OneToOne.class);
        if (ann2 != null) {return (ann2.fetch() == FetchType.LAZY);
        }
        ManyToOne ann3 = property.getAnnotation(ManyToOne.class);
        if (ann3 != null) {return (ann3.fetch() == FetchType.LAZY);
        }
        ManyToMany ann4 = property.getAnnotation(ManyToMany.class);
        if (ann4 != null) {return (ann4.fetch() == FetchType.LAZY);
        }
        // As per [Issue#53]
        return !Feature.REQUIRE_EXPLICIT_LAZY_LOADING_MARKER.enabledIn(_features);
    }
    return false;
}

发现我关联字段上应用的是 @ManyToMany(fetch = FetchType.EAGER),因为我之前为了解决懒加载就加上的,当初能够去掉了,问题也失去了解决。

退出移动版