9

构建 bean 后,我想使用 EntityManager 从数据库中检索数据。在构造函数中是不可能的,因为EntityManager是在构造函数被调用之后注入的。所以我尝试用@PostConstruct 注释的方法来做。根据 API,在所有注入完成后调用 PostConstruct 方法。执行查询有效,但它总是返回一个空列表。如果我在其他方法中使用相同的查询,它会返回正确的结果。有谁知道,为什么它在 PostConstruct 方法中不起作用?

@Stateful(mappedName = "price")
@Singleton
@Startup
public class PriceManagementBean implements PriceManagement {

    @PersistenceContext
    private EntityManager em;

    private List<PriceStep> priceSteps =  Collections.synchronizedList(new ArrayList<PriceStep>());


    public PriceManagementBean(){


    }


    @PostConstruct
    public void init(){
        javax.persistence.Query query = em.createQuery("SELECT ps FROM PriceStep ps");
        List<PriceStep> res = query.getResultList();
            .....
       }
}
4

2 回答 2

9

有谁知道,为什么它在 PostConstruct 方法中不起作用?

原因 1 你不能创建一个同时是 @Stateful 和 @Singleton 的 bean(你可以,但是因为 Singletons 也是有状态的,所以这没有意义),这是你遇到麻烦的原因之一。没有例外,但那里有冲突,你需要先解决这个问题。

只要记住:

  • Singleton bean 是一个保持其状态的 bean。应用程序中只有一个 Singleton 实例,它在应用程序的所有用户之间共享。此外,由于它是一个共享的(最好说是并发的)bean,因此需要使用 @Lock 注释来实现某种锁定机制。

  • 有状态 bean 是在事务后维护每个状态的 bean。当使用
    有状态 bean 时,每个用户都会获得一个 bean 的副本,该副本将持续与会话一样长 - 持续或直到调用带有 @Remove 注释的方法

原因 2 即使它有效,您也无法访问结果,因为您将它们存储在一个名为 res 的对象中,该对象只能从方法init()内部访问。我想您想将该返回值分配给变量priceSteps

无论如何,您的代码中有很多错误,因为没有说明一切。我不知道您的系统要求是什么,但在这里我会给您一个简单的解决方案,让您可以访问数据库:

我想您正试图以某种方式在 bean 的生命周期中返回数据,因为如果 bean 是@Stateful,您希望避免一次又一次地发送查询。问题是,您不必这样做,您仍然可以使您的 bean @Stateless并避免使用许多查询给您的数据库带来压力。您需要做的是创建一个@NamedQuery

因此,使用@NamedQuery注释您的实体PriceStep ,然后输入您编写的查询字符串。在此链接中,您将找到有关如何使用@NamedQueries的信息:http : //docs.oracle.com/cd/B31017_01/web.1013/b28221/ent30qry001.htm

我建议您的下一件事是将您的类PriceManagementBean注释为* @Stateless *。如果在每个请求中都创建了一个新的 entityManager,请不要担心,这根本不会给数据库带来压力,因为它与域模型交互。您不需要@PostConstruct,您只需在需要时调用您的@NamedQuery,仅此而已。应用服务器将缓存它并将其返回给每个需要它的用户,而无需一直与数据库交互。

这是一个代码片段:

@Entity
@NamedQuery(
    name="allPriceSteps",
    queryString="SELECT ps FROM PriceStep ps"
)
public class PriceStep implements Serializable {
...
}

现在豆:

@Stateless
public class PriceManagementBean implements PriceManagement {

    @PersistenceContext
    private EntityManager em;

    public List<PriceStep> getAllPriceSteps() {
         Query query =  em.createNamedQuery("allPriceSteps");
         return query.getResultList();
     }
}

我希望这很有用。如果您提供有关系统要求的更多信息,我们可以为您提供最佳实践建议。

于 2012-05-26T15:03:48.830 回答
-2

根据您的要求,请尝试以下

  • 删除@Stateful [不能同时使用两者]

  • @Startup 将在 APPLICATION INIT 期间初始化单例 bean [请注意应用程序未完全初始化]。这可能会导致加载 EntityManager 时出现一些问题,我假设 EntityManager 桥未完全初始化。尝试在应用程序启动完成后调用 init [ie,] Remove @Startup

于 2012-05-28T09:21:13.567 回答