Hibernate с Spring Boot и Kotlin нетерпеливо загружает весь граф объектов - PullRequest
1 голос
/ 26 сентября 2019

Я установил spring.jpa.open-in-view на false, и предупреждение больше не появляется в журнале, так что это не причина.

Весь граф объектов выбирается, как только find() илиfindById() метод выполняется, поэтому я не думаю, что он также вызван сериализацией (сущности не реализуют интерфейс Serializable в любом случае).

Все объектные отношения много-к-одному,и все сопоставления объектов аннотированы как ленивые.

Единственный способ, которым я смог избежать нетерпеливой загрузки, был выбор отдельных полей, а не целых объектов, но это отнимает много времени и хрупок, поэтому я 'я предпочитаю не использовать это решение.

Приложение использует Hibernate 5.3.7 и Spring Boot 2.1.0.У старого приложения у нас нет этой проблемы;он использует Hibernate 4.3.8 и не использует Spring Boot.

Вот код (уменьшенный из бизнес-кейса, чтобы попытаться определить проблему).

@Entity
@Table(name = "VT_Invoice")
class Invoice(
    @Id
    @Column(name = "InvoiceID")
    val invoiceId: Long
) {
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "EntityCode#ClientCore", referencedColumnName = "EntityCode#ClientCore")
    var client: Client? = null
}
@Entity
@Table(name = "VT_ClientCore")
class Client(
    @Id
    @Column(name = "EntityCode#ClientCore")
    val id: String
) {
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "EntityCode#Branch", referencedColumnName = "EntityCode#Branch")
    var branch: Branch? = null
}
@Entity
@Table(name = "VT_Branch")
class Branch(
    @Id
    @Column(name = "EntityCode#Branch")
    val id: String
)
interface InvoiceRepository : JpaRepository<Invoice, Long>
@Service
class InvoiceRetrievalService(
    @Autowired val invoiceRepository: InvoiceRepository
) {
    @PersistenceContext
    private lateinit var entityManager: EntityManager

    fun fetchInvoice(invoiceId: Long): Invoice {
        val hibernateInvoice = entityManager.find(Invoice::class.java, invoiceId)
        val springInvoice = invoiceRepository.findById(invoiceId)
        return hibernateInvoice
    }
}

РЕДАКТИРОВАТЬ

После отладки кода Hibernate оказывается, что активная загрузка запускается этим блоком кода внутри DefaultLoadEventListener.proxyOrLoad():

        if ( !persister.hasProxy() ) {
            return load( event, persister, keyToLoad, options );
        }

Реализация AbstractEntityPersister.hasProxy() отличается в двух версиях Hibernate.

Hibernate 4.3.8:

    public boolean hasProxy() {
        return entityMetamodel.isLazy();
    }

entityMetamodel.isLazy() имеет значение true, поэтому связаннаязагрузка объекта пропущена.

Hibernate 5.3.7:

    public boolean hasProxy() {
        // skip proxy instantiation if entity is bytecode enhanced
        return entityMetamodel.isLazy() && !entityMetamodel.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading();
    }

entityMetamodel.isLazy() имеет значение false, поэтому связанный объект загружен.Проверка на улучшение байт-кода оказывается несущественной.

Это то, что я смог получить в ходе расследования.Я не мог определить, почему две версии Hibernate инициализируют атрибут lazy по-разному;он записан в нескольких местах, но ни одна из установленных мной точек останова не была достигнута, поэтому я предполагаю, что она где-то инициализируется с помощью отражения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...