我将 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() - &gt; CategoryDaoImpl.findByOffered() - &gt;返回EshopBean.updateOfferedMerchandise()。我猜这两个都被注释为事务性的,findByOffered方法被注释为Required。然而,WildFly中的Hibernate表示没有会话(我认为它需要相同的事务上下文)。
问题摘要:我想保持merchnadise懒惰地初始化并纠正会话问题,因此带有商品的包在EshopBean.updateOfferedMerchandise()方法中被懒惰地初始化。我真的需要JOIN FETCH或将Lazy初始化设置为false吗?如何为此代码设置正确的交易以开始工作?
答案 0 :(得分:0)
当应用程序从Glassfish迁移到Wildfly上时会发生此问题。不幸的是,与EclipseLink不同,Wildfly的默认Hibernate JPA实现不允许您在关闭上下文后获取延迟关系。
许多解决方案建议使用热切的提取进行重构,但这不是一个好的解决方案,因为急切的提取会增加响应,并且您通过重构数据库访问将风险引入到工作的应用程序中。
而是将Hibernate替换为EclipseLink作为Wildfly中的JPA持久性提供程序。 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>
不要忘记重启服务器。