【问题标题】:Lazy initialization of ArrayList attribute fails (EclipseLink -> Hibernate migration)ArrayList 属性的延迟初始化失败(EclipseLink -> Hibernate 迁移)
【发布时间】:2014-08-19 20:51:52
【问题描述】:

我将 Java EE 战争网站从 GlassFish 4 迁移到 WildFly

Glassfish 使用 EclipseLink,WildFly 使用 Hibernate。我正在使用带有 CDI 命名 bean 的 Java Server Faces。我的一个 bean 直接调用 dao 类方法来检索 Category 对象。 Category 类有一些属性,其中之一是 List 商品。默认情况下,这是延迟初始化的(商品是另一个表)。检索到 Category 对象,但在尝试使用延迟初始化的 List 商品时,持久性包为空并引发以下错误:

javax.servlet.ServletException: failed to lazily initialize a collection of role: cz.pscheidl.velkoobchod.domain.Category.merchandise, could not initialize proxy - no Session

我想我知道这是什么问题。调用此对象时,名为 EshopBean 的 @Named bean 不提供任何事务。这在 Glassfish 中不应该起作用,但不知何故它确实起作用了。在 Category 对象中设置 List 商品的 EAGER 初始化后,一切正常。相关命名查询中的 JOIN FETCH 也是如此。

EshopBean 对象如下所示:

@Named
@ViewScoped
public class EshopBean implements Serializable {


    @Inject private CategoryDao categoryDao;
    @Inject private MerchandiseDao merchandiseDao;
    @Inject private ActiveSession activeSession;
    @Inject private OrderDao orderDao;
    @Inject private Logger logger;


    private List<Category> categoryList;
    private List<OrderItem> offeredMerchandise;


    @PostConstruct
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void updateOfferedMerchandise() {
        List<Category> allCateogries = categoryDao.findByOffered(true);
        offeredMerchandise = new ArrayList<>();
        categoryList = new ArrayList<>();

        allCateogries.parallelStream().filter(e -> {
        return !e.getMerchandise().isEmpty();
        }).forEach(e -> {
        categoryList.add(e);

        e.getMerchandise().parallelStream().filter(m -> {
            return m.isOffered();}).forEach(m -> {
            offeredMerchandise.add(createOrderItem(m));
            });

        });
    }
}

类别对象如下(省略方法):

@Entity
@NamedQueries(
        {
            @NamedQuery(name = "findCategoryByName", query = "SELECT c FROM Category c WHERE c.name = :name"),
            @NamedQuery(name = "findAllCategories", query = "SELECT c FROM Category c"),
            @NamedQuery(name = "categoryHasMerchandise", query = "SELECT COUNT(m) FROM Merchandise m WHERE m.category = :categoryId"),
            @NamedQuery(name = "findCategoryByOffered", query = "SELECT c FROM Category c WHERE c.offered = :offered")
        }
)
public class Category implements Serializable {


    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    @Column(unique = true)
    @Size(min = 1, max = 255)
    private String name;
    @Column(nullable = false)
    private boolean offered;
    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    @JoinColumn(name = "CATEGORY_ID")
    public List<Merchandise> merchandise;
}

CategoryDaoImpl(部分方法省略):

@Stateless
public class CategoryDaoImpl implements CategoryDao {
    @PersistenceContext
    private EntityManager entityManager;

    @Override
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public List<Category> findByOffered(boolean activity) {
        Query findByOfferedQuery = entityManager.createNamedQuery("findCategoryByOffered", Category.class);
        findByOfferedQuery.setParameter("offered", true);
        return findByOfferedQuery.getResultList();
    }
}

方法调用链是这样的:EshopBean.updateOfferedMerchandise() -> CategoryDaoImpl.findByOffered() -> 返回EshopBean.updateOfferedMerchandise()。我猜两者都被注释为事务性的,findByOffered 方法被注释为必需的。然而 WildFly 中的 Hibernate 说没有会话(我认为它需要相同的事务上下文)。

问题总结: 我想保持merchnadise 延迟初始化并纠正session 问题,所以在EshopBean.updateOfferedMerchandise() 方法中延迟初始化带有商品的包。我真的需要 JOIN FETCH 或将延迟初始化设置为 false 吗?如何设置正确的事务以使此代码开始工作?

【问题讨论】:

  • JOIN FETCH 将是正确的过程。
  • 关于你的第二个问题,我没有得到你想问的问题?

标签: hibernate jakarta-ee eclipselink wildfly


【解决方案1】:

当应用程序从 Glassfish 迁移到 Wildfly 时,会出现此问题。不幸的是,Wildfly 的默认 Hibernate JPA 实现不允许您在上下文关闭后获取惰性关系,这与 EclipseLink 不同。

许多解决方案建议使用 Eager fetch 进行重构,但这不是一个好的解决方案,因为 Eager fetch 会增加响应,并且您会通过重构数据库访问将风险引入工作应用程序。

宁可将 Hibernate 替换为 EclipseLink 作为 Wildfly 中的 JPA Persistence Provider。 This library 的实用程序类将 EclipseLink 集成到 Wildfly 和 the instructions are here

你要做的就是把 eclipselink-2.6.0.jar(或者你正在使用的任何版本)复制到 [WILDFLY_HOME]/modules/system/layers/base/org/ eclipse/persistence/main,然后在同一文件夹中编辑 module.xml 以包含 JAR:

<resources>
   <resource-root path="jipijapa-eclipselink-1.0.1.Final.jar"/>
   <resource-root path="eclipselink-2.6.0.jar">           
      <filter>
         <exclude path="javax/**" />
      </filter>
   </resource-root>
</resources>

别忘了重启服务器。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多