2012-04-23 95 views
0

为什么我不能通过使用@Transactional注释返回的方法获得ID为session.load(product.class,1)的实体对象product.getName()的值?当我以这种方式获得产品对象时session.createQuery("from Product as product WHERE product.id = 1)一切都很好。休眠对象生命周期

编辑

道法

public Product getProduct(Long id) { 
return (Product) currentSession().load(Product.class, id); 
} 

服务方法

@Transactional 
public Product getProduct(Long id) { 
    return productDao.getProduct(id); 
} 

控制方法 - 它应该发送JSON,但它与错误打破上product.getName()org.hibernate.LazyInitializationException: could not initialize proxy - no Session

@RequestMapping(value = "/product",headers="Accept=application/json") 
public @ResponseBody Product getProduct() { 
    Product product = productService.getProduct(new Long(1)); 
    System.out.println(product.getName()); 
    return product; 
} 
+0

你必须告诉一点点。在通过'session.load(product.class,1)'加载产品后调用'product.getName()'时发生了什么?产品对象是否可能是Product类的缓存实例?你能发布你的代码的相关部分吗? – andih 2012-04-23 19:49:13

回答

0

如果在会话范围之外访问未初始化的集合或代理,即拥有集合的实体或对代理的引用处于分离状态时,Hibernate将抛出A LazyInitializationException

有时代理或集合需要在关闭会话之前进行初始化。您可以通过调用product.getName()或例如强制初始化。但是,这可能会让代码读者感到困惑,而且对于通用代码来说并不方便。

静态方法Hibernate.initialize()Hibernate.isInitialized(),提供延迟加载集合或代理的一种便捷方式申请。只要其会话仍处于打开状态,Hibernate.initialize(product)将强制代理的初始化,即product

您也可以声明领域的一些是eagely loaded

@Entity 
public class Product { 

    @Id 
    @GeneratedValue 
    private long id; 


    @Basic(fetch=EAGER) 
    private String name; 


} 
+0

也许我没有具体说明我想要做什么。我想从数据库加载产品并将其属性发送给浏览器。什么是正确的方法来做到这一点? – user1137146 2012-04-23 20:38:39

+1

一种方法是在返回'product'之前将'Hibernate.initialize(product)'行放入DAO中。或者你可以在产品实体上简单地写'@ org.hibernate.annotations.Proxy(lazy = false)',它完全禁止延迟加载你的Product实体的所有属性。 – andih 2012-04-23 20:51:34

-1

当我们在我们的Java code, the instance is considered to be a transient instance中创建实例时,这意味着没有适当的机制来管理该实例的持久状态。 但是,一旦we pass a transient instance to the save, update, or saveOrUpdate method of the Hibernate Session,我们认为瞬态实例已转换为持久实例,因为Hibernate将开始管理该实例的持久状态。

任何与Hibernate Session关联的实例都被认为是一个持久实例。

保存或更新JavaBean并不是获得持久实例的唯一方法。 已通过get或load方法调用或HQL或条件查询加载到Hibernate Session中的JavaBean被视为持久实例,因此,对这些实例状态的任何更改或更新将会也可以通过Hibernate Session持久化到数据库。

如果你确实有一个你想从Hibernate控件发布的实例,你总是可以调用Hibernate Session的evict方法,传递你想从Hibernate控件中释放的实例名称。当一个实例不再具有由Hibernate Session管理的状态时,我们称之为分离实例,因为虽然它在数据库中具有表示,但Hibernate没有做任何事情来保持实例与基础持久性存储的同步。实际上,该实例与数据库中的相应表示分离。

当然,当我们使用Hibernate时,我们与数据库的所有交互必须发生在事务的范围内。默认情况下,当我们调用save或update之类的方法时,我们永远无法完全确定数据库中相应的记录何时更新 - 我们所知道的确实是一旦事务被提交,所有对持久化与Hibernate Session关联的实例将被保存到数据库中。当然,由于某种原因,将所有数据保存到数据库的行为总是有可能失败,如果发生这种情况,Hibernate会抛出一个运行时异常。

在这一点上,除了回滚当前事务并关闭休眠会话之外,并没有太多可以做的事情。此时,之前在Hibernate Session控制下的所有实例都成为分离对象,并且很可能不再与数据库同步。在这种情况下,你总是可以开始一个新的事务,并尝试通过保存或更新调用将它们与Hibernate Session重新关联来尝试将已分离的实例恢复为持久化实例,但最终可能会更好只需向您的客户端应用程序发送友好的错误消息,并从头开始重新开始任何请求 - 响应循环。 简单描述了我们在谈论瞬态,持久和分离对象时的含义。