EJB:在PostConstruct方法中使用EntityManager

时间:2012-04-30 14:18:37

标签: java ejb entitymanager

构造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();
            .....
       }
}

2 个答案:

答案 0 :(得分: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 {
...
}

现在是bean:

@Stateless
public class PriceManagementBean implements PriceManagement {

    @PersistenceContext
    private EntityManager em;

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

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

答案 1 :(得分:-2)

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

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

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