Spring & Hibernate: почему выборка 1 ленивое поле запускает загрузку всех других ленивых полей - PullRequest
1 голос
/ 16 апреля 2020

В моем приложении есть объект Staff с несколькими полями с отложенной загрузкой, подобными этим.

@Entity(name="CommonStaff")
@Table(name="staff")
@Getter @Setter
public class Staff implements Serializable {
    ...

    @ManyToOne(fetch=FetchType.LAZY)
    @LazyToOne(LazyToOneOption.NO_PROXY)
    @JoinColumn(name="nationality", referencedColumnName="code", insertable=false, updatable=false)
    private Nationality nationality;

    @ManyToOne(fetch=FetchType.LAZY)
    @LazyToOne(LazyToOneOption.NO_PROXY)
    @JoinColumn(name="marital_status", referencedColumnName="code", insertable=false, updatable=false)
    private MaritalStatus maritalStatus;

    ...
}

Когда я загружаю запись Staff, ни одно из этих полей не загружается с нетерпением как и ожидалось. Однако, когда я запускаю, например, getNationality(), я вижу, как фреймворк выполняет SQL для загрузки MaritalStatus. Я пытался найти способ исправить это, но я не мог найти какой-либо полезный ресурс. Я был бы очень признателен, если бы вы указали мне направление.

Пример кода.

@Autowired
@Qualifier("dataModuleStaffRepo")
private StaffRepo staffRepo;

@CustomerTransactional
@GetMapping("/profile")
public void testProfile(@RequestParam String userId) {
    Optional<Staff> staff = staffRepo.findByUserId(userId);
    if (staff.isPresent()) {
        System.out.println(staff.get().getName());
        System.out.println(staff.get().getNationality().getName());
    }
}

Ниже приведено то, что я вижу в консоли. После того, как имя сотрудника было напечатано, getNationality() также вызвало загрузку MaritalStatus.

Edgar Rey Tann
2020-04-16 14:29:40,283 DEBUG [http-nio-9000-exec-2] org.hibernate.SQL   : 
    /* sequential select
        com.ft.common.db.customer.domain.Staff */ select
            staff_.marital_status as marital19_23_,
            staff_.nationality as nationa22_23_
        from
            staff staff_ 
        where
            staff_.id=?
2020-04-16 14:29:40,283 TRACE [http-nio-9000-exec-2] org.hibernate.type.descriptor.sql.BasicBinder   : binding parameter [1] as [BIGINT] - [660]
2020-04-16 14:29:40,291 DEBUG [http-nio-9000-exec-2] org.hibernate.SQL   : 
    /* load com.ft.common.db.customer.domain.MaritalStatus */ select
        maritalsta0_.id as id1_9_0_,
        maritalsta0_.code as code2_9_0_,
        maritalsta0_.description as descript3_9_0_,
        maritalsta0_.name as name4_9_0_,
        maritalsta0_.order_id as order_id5_9_0_,
        maritalsta0_.short_name as short_na6_9_0_ 
    from
        marital_status maritalsta0_ 
    where
        maritalsta0_.code=?
2020-04-16 14:29:40,291 TRACE [http-nio-9000-exec-2] org.hibernate.type.descriptor.sql.BasicBinder   : binding parameter [1] as [VARCHAR] - [MAR_2]
2020-04-16 14:29:40,298 DEBUG [http-nio-9000-exec-2] org.hibernate.SQL   : 
    /* load com.ft.common.db.customer.domain.Nationality */ select
        nationalit0_.id as id1_16_0_,
        nationalit0_.code as code2_16_0_,
        nationalit0_.description as descript3_16_0_,
        nationalit0_.name as name4_16_0_,
        nationalit0_.order_id as order_id5_16_0_,
        nationalit0_.short_name as short_na6_16_0_ 
    from
        nationality nationalit0_ 
    where
        nationalit0_.code=?
2020-04-16 14:29:40,298 TRACE [http-nio-9000-exec-2] org.hibernate.type.descriptor.sql.BasicBinder   : binding parameter [1] as [VARCHAR] - [NAT_I]
Indonesian

1 Ответ

2 голосов
/ 16 апреля 2020

По умолчанию все ленивые свойства класса сущности принадлежат группе с именем DEFAULT. А извлечение любого свойства из группы DEFAULT извлекает и другие. Чтобы решить эту проблему, нам нужно определить группы, которые мы будем sh выбирать отдельно, используя аннотацию @LazyGroup.

Итак, мы помечаем и национальность, и maritalStatus с аннотацией @LazyGroup, как показано ниже.

@ManyToOne(fetch=FetchType.LAZY)
@LazyToOne(LazyToOneOption.NO_PROXY)
@LazyGroup("nationality")
@JoinColumn(name="nationality", referencedColumnName="code", insertable=false, updatable=false)
private Nationality nationality;

@ManyToOne(fetch=FetchType.LAZY)
@LazyToOne(LazyToOneOption.NO_PROXY)
@LazyGroup("maritalStatus")
@JoinColumn(name="marital_status", referencedColumnName="code", insertable=false, updatable=false)
private MaritalStatus maritalStatus;

И, надеюсь, вы используете улучшение байт-кода для отложенной выборки без прокси

...