gpt4 book ai didi

java - 为什么 Hibernate JPA 在使用 getReference() 时抛出 LazyInitialization 异常?

转载 作者:行者123 更新时间:2023-12-02 12:11:39 26 4
gpt4 key购买 nike

我使用 Hibernate 5.2.11 作为 JPA 提供程序。我有一个带注释的类 (PurchaseOrder) 和另一个带注释的类 (Customer) 作为具有多对一关系的字段。但因为遗留代码在不同的数据库中具有 Customer 和 PO 表,所以我在 PurchasingOrder 中调用 EntityManager 的 getReference() 以返回 Customer 实例。我通过使用 Hibernate 的自制类访问这些内容(详细信息如下)。这会导致以下异常:

org.hibernate.LazyInitializationException:无法初始化代理 - 无 session

我一直在阅读 Hibernate、JPA 和 Java EE 文档,但一直无法弄清楚我做错了什么。我知道 Hibernate 在幕后使用 Session 来启用 JPA 功能,但是当我访问 .getCustomer() 时,我正在创建一个新的 EntityManager,因此它应该具有所需的 session 。

很明显,我缺少一个关键的理解,但我不知道它是什么。谁能帮我解答一下吗?

这是采购订单的重要部分,它由字符串、整数、 boolean 值和 LocalDates 组成(即:它们都是 @Basic 字段),而 Customer 作为唯一包含的类:

@Entity
@Table(name = "PurchaseOrder")
public class PurchaseOrder extends BaseEntity { // BaseEntity is a @mappedSuperclass containing the primary key info only.
...
private Integer customerID;
private Customer customer;
...
@Column(name = "customerID")
public Integer getCustomerID() {
return customerID;
}

public void setCustomerID(Integer customerID) {
this.customerID = customerID;
}

@Transient
public Customer getCustomer() {
LOG.info("Getting customer #{}", customerID);
if (customerID != 0 && (customer == null || !customerID.equals(customer.getId()))) {
customer = VdtsSysDB.getDB().get(Customer.class, customerID);
}
return customer;
}

public void setCustomer(Customer customer) {
this.customer = customer;
this.customerID = customer.getId();
}
...

这是客户,仅包含 @Basic 字段:

@Entity
@Table(name = "Customers")
public class Customer extends BaseEntity{
private String custNo;
private String businessName;
private String contact;
...
@Column(name = "custNo")
public String getCustNo() {
return custNo;
}

public void setCustNo(String custNo) {
this.custNo = custNo;
}

@Column(name = "Name")
public String getBusinessName() {
return businessName;
}

public void setBusinessName(String businessName) {
this.businessName = businessName;
}

@Column(name = "Contact")
public String getContact() {
return contact;
}

public void setContact(String contact) {
this.contact = contact;
}
...

这是我的 Hibernate 实用程序类:

public class VdtsSysDB {
private EntityManagerFactory entityManagerFactory;
private static VdtsSysDB vdtsSysDB;

public static VdtsSysDB getDB() {
if (vdtsSysDB == null) {
vdtsSysDB = new VdtsSysDB();
}
return vdtsSysDB;
}

private VdtsSysDB() {
if (entityManagerFactory == null)
entityManagerFactory = Persistence.createEntityManagerFactory("VDTS_SYSDB");
}

public EntityManager getEntityManager() {
return entityManagerFactory.createEntityManager();
}

public void closeEntityManager(EntityManager entityManager) {
try {
entityManager.close();
} catch (Exception e) {
// Exception logging.
}
}
...
/**
* Issues an HQL Query and returns the results as a list.
*
* @param queryString - An HQL query.
* @return A list of items representing the returned dataset.
*/
public <T extends BaseEntity> List<T> query(String queryString) {
List<T> results = null;
LOG.info("Query: {}", queryString);
EntityManager entityManager = null;
try {
entityManager = getEntityManager();
results = entityManager.createQuery(queryString).getResultList();
entityManager.close();
LOG.info("Returned {} results.", results.size());
} catch (Exception e) {
if (entityManager != null && entityManager.isOpen()) entityManager.close();
LOG.error("Unable to complete query {}.", queryString, e);
}
return results;
}

/**
* Get an object from the database by specifying its class and its ID.
* @param aClass the class type to be returned.
* @param id the primary key to the item to be returned.
* @param <T> the class type to be returned.
* @return A single instance of the specified item of this class.
*/
public <T extends BaseEntity> T get(Class aClass, Integer id) {
LOG.info("Get #: {}, {}", id, aClass.getName());
T result = null;
EntityManager entityManager = null;
try {
entityManager = getEntityManager();
Object object = entityManager.getReference(aClass, id);
result = (T) object;
} catch (Exception e) {
LOG.error("Could not get {}", id, e);
} finally {
closeEntityManager(entityManager);
}
return result;
}
}

引发异常的代码是 JavaFX 8 应用程序 Controller 的一部分。在类加载时调用initialize(),而在显示附加的GUI 时调用refreshPane()。调用 Customer.getBusinessName() 时会引发异常。

@FXML
private TableView<PurchaseOrder> poTable;
@FXML
private TableColumn<PurchaseOrder, String> poNoCol;
@FXML
private TableColumn<PurchaseOrder, String> customerNameCol;
@FXML
private TableColumn<PurchaseOrder, LocalDate> orderDateCol;

@Override
protected void initialize() {
super.initialize();
poTable.getSelectionModel().selectedItemProperty().addListener(
(observable, oldValue, newValue) -> {
if (newValue != null) selectItem();
});
poNoCol.setCellValueFactory(new PropertyValueFactory<>("purchaseOrderNo"));
customerNameCol.setCellValueFactory(param -> {
PurchaseOrder po = param.getValue();
Customer customer = po.getCustomer();
String name = customer.getBusinessName(); /****** This is the line that throws the exception ******/
StringProperty observableString = new SimpleStringProperty(name);
return observableString;
});
orderDateCol.setCellValueFactory(new PropertyValueFactory<>("orderDate"));
...
}

@Override
protected void refreshPane() {
List<Customer> oList = VdtsSysDB.getDB().query("from Customer");
customerCombo.setItems(FXCollections.observableList(oList));
changeTable();
clearWidgets();
enableWidgets(false);
}

private void changeTable() {
poTable.getSelectionModel().clearSelection();
List<PurchaseOrder> oList = VdtsSysDB.getDB()
.query("from PurchaseOrder where closed = " + (openRadio.isSelected() ? "0" : "1"));
poTable.setItems(FXCollections.observableList(oList));
}
...

异常的完整堆栈跟踪:

30-09-17 19:42:05.137 ERROR java.lang.Throwable - Exception in thread "JavaFX Application Thread" org.hibernate.LazyInitializationException: could not initialize proxy - no Session
30-09-17 19:42:05.137 ERROR java.lang.Throwable - at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:146)
30-09-17 19:42:05.138 ERROR java.lang.Throwable - at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:259)
30-09-17 19:42:05.139 ERROR java.lang.Throwable - at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:73)
30-09-17 19:42:05.139 ERROR java.lang.Throwable - at ca.vdts.buchanan.model.Customer_$$_jvst799_9.getBusinessName(Customer_$$_jvst799_9.java)
30-09-17 19:42:05.139 ERROR java.lang.Throwable - at ca.vdts.buchanan.endtally.controllers.POController.lambda$initialize$1(POController.java:103)
30-09-17 19:42:05.140 ERROR java.lang.Throwable - at javafx.scene.control.TableColumn.getCellObservableValue(TableColumn.java:578)
30-09-17 19:42:05.140 ERROR java.lang.Throwable - at javafx.scene.control.TableColumn.getCellObservableValue(TableColumn.java:563)
30-09-17 19:42:05.140 ERROR java.lang.Throwable - at javafx.scene.control.TableCell.updateItem(TableCell.java:644)
30-09-17 19:42:05.141 ERROR java.lang.Throwable - at javafx.scene.control.TableCell.indexChanged(TableCell.java:468)
30-09-17 19:42:05.141 ERROR java.lang.Throwable - at javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:116)
30-09-17 19:42:05.141 ERROR java.lang.Throwable - at com.sun.javafx.scene.control.skin.TableRowSkinBase.updateCells(TableRowSkinBase.java:533)
30-09-17 19:42:05.141 ERROR java.lang.Throwable - at com.sun.javafx.scene.control.skin.TableRowSkinBase.init(TableRowSkinBase.java:147)
30-09-17 19:42:05.142 ERROR java.lang.Throwable - at com.sun.javafx.scene.control.skin.TableRowSkin.<init>(TableRowSkin.java:64)
30-09-17 19:42:05.142 ERROR java.lang.Throwable - at javafx.scene.control.TableRow.createDefaultSkin(TableRow.java:212)
30-09-17 19:42:05.142 ERROR java.lang.Throwable - at javafx.scene.control.Control.impl_processCSS(Control.java:872)
30-09-17 19:42:05.142 ERROR java.lang.Throwable - at javafx.scene.Node.processCSS(Node.java:9058)
30-09-17 19:42:05.143 ERROR java.lang.Throwable - at javafx.scene.Node.applyCss(Node.java:9155)
30-09-17 19:42:05.143 ERROR java.lang.Throwable - at com.sun.javafx.scene.control.skin.VirtualFlow.setCellIndex(VirtualFlow.java:1964)
30-09-17 19:42:05.143 ERROR java.lang.Throwable - at com.sun.javafx.scene.control.skin.VirtualFlow.getCell(VirtualFlow.java:1797)
30-09-17 19:42:05.143 ERROR java.lang.Throwable - at com.sun.javafx.scene.control.skin.VirtualFlow.getCellLength(VirtualFlow.java:1879)
30-09-17 19:42:05.144 ERROR java.lang.Throwable - at com.sun.javafx.scene.control.skin.VirtualFlow.computeViewportOffset(VirtualFlow.java:2528)
30-09-17 19:42:05.144 ERROR java.lang.Throwable - at com.sun.javafx.scene.control.skin.VirtualFlow.layoutChildren(VirtualFlow.java:1189)
30-09-17 19:42:05.144 ERROR java.lang.Throwable - at javafx.scene.Parent.layout(Parent.java:1087)
30-09-17 19:42:05.144 ERROR java.lang.Throwable - at javafx.scene.Parent.layout(Parent.java:1093)
30-09-17 19:42:05.145 ERROR java.lang.Throwable - at javafx.scene.Parent.layout(Parent.java:1093)
30-09-17 19:42:05.145 ERROR java.lang.Throwable - at javafx.scene.Parent.layout(Parent.java:1093)
30-09-17 19:42:05.145 ERROR java.lang.Throwable - at javafx.scene.Parent.layout(Parent.java:1093)
30-09-17 19:42:05.145 ERROR java.lang.Throwable - at javafx.scene.Parent.layout(Parent.java:1093)
30-09-17 19:42:05.146 ERROR java.lang.Throwable - at javafx.scene.Parent.layout(Parent.java:1093)
30-09-17 19:42:05.146 ERROR java.lang.Throwable - at javafx.scene.Parent.layout(Parent.java:1093)
30-09-17 19:42:05.146 ERROR java.lang.Throwable - at javafx.scene.Parent.layout(Parent.java:1093)
30-09-17 19:42:05.147 ERROR java.lang.Throwable - at javafx.scene.Scene.doLayoutPass(Scene.java:552)
30-09-17 19:42:05.147 ERROR java.lang.Throwable - at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2397)
30-09-17 19:42:05.147 ERROR java.lang.Throwable - at com.sun.javafx.tk.Toolkit.lambda$runPulse$30(Toolkit.java:355)
30-09-17 19:42:05.147 ERROR java.lang.Throwable - at java.security.AccessController.doPrivileged(Native Method)
30-09-17 19:42:05.148 ERROR java.lang.Throwable - at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:354)
30-09-17 19:42:05.148 ERROR java.lang.Throwable - at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:381)
30-09-17 19:42:05.148 ERROR java.lang.Throwable - at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:510)
30-09-17 19:42:05.148 ERROR java.lang.Throwable - at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:490)
30-09-17 19:42:05.149 ERROR java.lang.Throwable - at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$404(QuantumToolkit.java:319)
30-09-17 19:42:05.149 ERROR java.lang.Throwable - at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
30-09-17 19:42:05.150 ERROR java.lang.Throwable - at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
30-09-17 19:42:05.150 ERROR java.lang.Throwable - at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
30-09-17 19:42:05.150 ERROR java.lang.Throwable - at java.lang.Thread.run(Thread.java:745)

最佳答案

哦。为什么你只有在发布问题后才能找到答案?

由于我使用 EntityManager.getReference(),因此引发了此异常。

来自 Java EE JPA Javadocs:

Get an instance, whose state may be lazily fetched. If the requested instance does not exist in the database, the EntityNotFoundException is thrown when the instance state is first accessed. (The persistence provider runtime is permitted to throw the EntityNotFoundException when getReference is called.) The application should not expect that the instance state will be available upon detachment, unless it was accessed by the application while the entity manager was open.

我试图访问 Customer 的字段,getReference 是延迟获取的。在我关闭 EntityManager 之前这些字段尚未初始化,因此任何引用它们的尝试都必然会引发 LazyInitialization 异常。

这里的解决方案很明显:不要使用 getReference。请改用 EntityManager.find()。

关于java - 为什么 Hibernate JPA 在使用 getReference() 时抛出 LazyInitialization 异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46508036/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com