【问题标题】:How to avoid the LazyInitializationException when submitting a form in JSF?在 JSF 中提交表单时如何避免 LazyInitializationException?
【发布时间】:2019-08-11 08:46:24
【问题描述】:

我在某些实体之间存在多对多关系。我正在尝试从编辑页面更新对象,但是当我单击提交按钮时(我使用的是 jsf 的 commandLinkbut 但从动作属性引用的方法内部为空)休眠给了我一个延迟初始化异常。

org.hibernate.LazyInitializationException: failed to lazily initialize a collection, could not initialize proxy - no Session

工作流程如下:我列出了表格上的所有对象,然后单击特定对象进行编辑(它会将我带到另一个页面)。我从使用 HibernateGenericDAO 中的方法 findByAll 的 DAO 调用方法 getAllCases 的服务中使用方法 getAllCases() 获取所有对象。

这里是主要实体:

@Entity
@Table(name = "table")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Case implements Serializable, commons.entities.Entity<Long> {

private List<Product> products;

  @ManyToMany(fetch = FetchType.LAZY)
  @Cascade(CascadeType.SAVE_UPDATE)
  @JoinTable(
      name = "join_table",
      joinColumns = {@JoinColumn(name = "CASE_ID", nullable = false, updatable = false)},
      inverseJoinColumns = {@JoinColumn(name = "PRODUCT_ID", nullable = false, updatable = false)},
      uniqueConstraints = {@UniqueConstraint(columnNames = {"CASE_ID", "PRODUCT_ID"})}
  )
  public List<Product> getProducts() {
    return products;
  }

  public void setProducts(List<Product> products) {
    this.products = products;
  }

这是 Product 实体。

@Entity
@Table(name = "table")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Product implements Serializable, commons.entities.Entity<Long> {

  private Long id;
  private String productName;

  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "PRODUCTS_seq")
  @SequenceGenerator(name = "CASE_PRODUCTS_seq", sequenceName = "PRODUCTS_seq", allocationSize = 1)
  public Long getId() {
    return id;
  }

  public void setId(Long id) {
    this.id = id;
  }

  @Column(name = "product_name", unique = true, nullable = false)
  public String getProductName() {
    return productName;
  }

  public void setProductName(String productName) {
    this.productName = productName;
  }

这是服务

@Component
@Transactional(
    propagation = Propagation.REQUIRES_NEW,
    rollbackFor = {
        RuntimeException.class,
        Exception.class,
        UnexpectedRollbackException.class
    })
public class CasesService {

  @Autowired
  public CasesService(ICaseDAO caseDAO) {
    this.caseDAO = caseDAO;
  }

 public void saveCase(Case case) {
    caseDAO.saveCase(case);
  }

这是 DAO

@Component
public class CaseDAO extends HibernateGenericDAO<Long, Case> implements ICaseDAO {

@Override
  public List<Case> getAllCases() {
    return this.findByAll();
  }

@Override
  public void saveCase(Case case) {
    this.merge(case);
  }
}

【问题讨论】:

  • 您将不得不重新获取(刷新)实体,因为它是在不同的(上一个)事务中获取的。
  • 没有更优雅的解决方案吗?
  • @Priyesh: 或者合并...
  • @ericgramirez 记得标记你想回复的人。

标签: java hibernate jsf


【解决方案1】:

您可以尝试激活hibernate.enable_lazy_load_no_trans configuration property

但最好使用当前用户交互所需的所有数据初始化 DTO 对象。

认真对待设置的提示:

在给定的事务持久性上下文之外初始化惰性代理或集合。

虽然启用此配置可​​以使LazyInitializationException消失,但最好使用获取计划 保证所有属性在之前正确初始化 会话已关闭。

实际上,无论如何您都不应该启用此设置。

一般来说,设置(当true时)增强了延迟加载机制,如果原始Session实体已被提取,它将在每次延迟初始化时创建一个新的TX->fetch->commit循环closed.

【讨论】:

  • 当您知道再次需要实体时,“只是”进行合并怎么样?
  • @ericgramirez 我引用了,是的。
  • @Selaron 没有其他解决方案吗?
猜你喜欢
  • 1970-01-01
  • 2020-11-19
  • 1970-01-01
  • 2021-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多