意外的 JavaAssistLazyInitializer 即使使用 INNER JOIN FETCH 查询

Unexpected JavaAssistLazyInitializer even with INNER JOIN FETCH Query

我需要将名为 tabPremissa 的嵌套字段提取到 Premissa 模型中,但我无法处理 JavaAssistLazyInitializer。

我已经试过了

  1. 使用 ((HibernateProxy) entity).getHibernateLazyInitializer().getImplementation()
  2. 取消代理惰性字段
  3. INNER JOIN FETCH JpaRepository 方法

代码如下:

Premissa.java

@Entity
@Table(name = "premissa")
public class Premissa implements Draggable {

    @Id
    @SequenceGenerator(name = SEQ, sequenceName = SEQ, allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQ)
    @Column(name = "id")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "id_subcategoria_premissa", nullable=false)
    private SubCategoriaPremissa subCategoriaPremissa;
}

子类别Premissa.java

@Entity
@Table(name = "subcategoria_premissa")
public class SubCategoriaPremissa implements Draggable {

    @Id
    @SequenceGenerator(name = SEQ, sequenceName = SEQ, allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQ)
    @Column(name = "id")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "id_tab_premissa", nullable=false)
    private TabPremissa tabPremissa;
}

@查询

String QUERY_TAB_ORDER_BY_TAB_AND_ORDER = " SELECT P From Premissa P "
                                        + " INNER JOIN FETCH P.subCategoriaPremissa SCP "
                                        + " INNER JOIN FETCH SCP.tabPremissa TP "
                                        + " WHERE TP in :tabs "
                                        + " ORDER BY SCP.tabPremissa, P.ordem ";

休眠日志

    select
        premissa0_.id as id1_70_0_,
        subcategor1_.id as id1_85_1_,
        tabpremiss2_.id as id1_86_2_,
        premissa0_.campo_1 as campo_2_70_0_,
        premissa0_.campo_2 as campo_3_70_0_,
        premissa0_.campo_3 as campo_4_70_0_,
        premissa0_.campo_4 as campo_5_70_0_,
        premissa0_.id_centro_custo as id_cent15_70_0_,
        premissa0_.considera_zero as consider6_70_0_,
        premissa0_.descricao as descrica7_70_0_,
        premissa0_.id_empresa as id_empr16_70_0_,
        premissa0_.id_grupo_economico as id_grup17_70_0_,
        premissa0_.id_clone as id_clone8_70_0_,
        premissa0_.logica_totalizador as logica_t9_70_0_,
        premissa0_.nome as nome10_70_0_,
        premissa0_.ordem as ordem11_70_0_,
        premissa0_.id_pai as id_pai18_70_0_,
        premissa0_.style_table as style_t12_70_0_,
        premissa0_.id_subcategoria_premissa as id_subc19_70_0_,
        premissa0_.tipo_operacao_premissa as tipo_op13_70_0_,
        premissa0_.unidade_medida as unidade14_70_0_,
        subcategor1_.id_clone as id_clone2_85_1_,
        subcategor1_.label_1 as label_3_85_1_,
        subcategor1_.label_2 as label_4_85_1_,
        subcategor1_.label_3 as label_5_85_1_,
        subcategor1_.label_4 as label_6_85_1_,
        subcategor1_.nome as nome7_85_1_,
        subcategor1_.ordem as ordem8_85_1_,
        subcategor1_.id_pai as id_pai9_85_1_,
        subcategor1_.id_tab_premissa as id_tab_10_85_1_,
        tabpremiss2_.id_categoria_premissa as id_categ8_86_2_,
        tabpremiss2_.definicao_json as definica2_86_2_,
        tabpremiss2_.enum_link_id as enum_lin3_86_2_,
        tabpremiss2_.hexa_bg_color as hexa_bg_4_86_2_,
        tabpremiss2_.nome as nome5_86_2_,
        tabpremiss2_.ordem as ordem6_86_2_,
        tabpremiss2_.id_pai as id_pai9_86_2_,
        tabpremiss2_.status_edit as status_e7_86_2_ 
    from
        premissa premissa0_ 
    inner join
        subcategoria_premissa subcategor1_ 
            on premissa0_.id_subcategoria_premissa=subcategor1_.id 
    inner join
        tab_premissa tabpremiss2_ 
            on subcategor1_.id_tab_premissa=tabpremiss2_.id 
    where
        tabpremiss2_.id in (
            ? , ?
        ) 
    order by
        subcategor1_.id_tab_premissa,
        premissa0_.ordem

编辑

我直接在数据库中搜索了一个示例,其中 Premissa p 有一个 SubcategoriaPremissa s 和 运行 以下命令:

  1. s = subCategoriaPremissaRepository.findOne(1883L);

  2. p = premissaRepository.findOne(9019L);

在这种情况下,每个数据都正确加载并且s位于p中。 但是,如果执行顺序发生变化,调试时 s 被认为是 JavaAssistLazyInitializer

您最有可能遇到的问题是 Hibernate 无法将获取的状态合并到您的一级缓存中已经存在的现有对象中 a.k.a。你的 EntityManager/Session。因此,如果您以某种方式将实体代理放入 EntityManager/Session,后续查询是否获取该实体并不重要,结果将始终是代理。 Hibernate 必须遵守 JPA 规范,该规范粗略地说,具有相同主键的托管实体在 EntityManager/Session.

中只能存在一次对象标识方式

这是 IMO 避免 OSIV(Open-Session-In-View) 反模式的最大原因之一,但很少被提及。 Hibernate 可能会在某个时候修复此问题,但目前,它的行为是这样的。

所以你现在可以做的一件事是调用 EntityManager.clear() 来清除整个一级缓存或 EntityManager.detach() 以有问题的实体作为参数,从一级缓存中删除它.