【问题标题】:How to handle persistence context (EntityManager) with jax-rs sub-resource locators?如何使用 jax-rs 子资源定位器处理持久性上下文(EntityManager)?
【发布时间】:2011-04-20 18:12:23
【问题描述】:

我在我的应用程序中使用 jax-rs restful web 服务和子资源定位器。但是,在将 entityManager 传递给子资源后,我无法在此子资源中保留任何新对象。

entityManager 让我可以查询它的数据。

这是我的主要资源:

@Path("/registrations")
@Stateless
public class RegistrationsResource {

    @Context
    private UriInfo context;

    @PersistenceContext(unitName="pctx")
    private EntityManager em;

    public RegistrationsResource() {
    }

    //POST method ommited

    @Path("{regKey}")
    public RegistrationResource getRegistrationResource(@PathParam("regKey")
    String regKey) {
        return RegistrationResource.getInstance(regKey, em);
    }

}

这是我的子资源:

public class RegistrationResource {

    private String regKey;
    private EntityManager em;

    private RegistrationResource(String regKey, EntityManager em) {
        this.regKey = regKey;
        this.em = em;
    }

    @Path("securityQuestion")
    @GET
    public String getQuestion() {
        return "iamahuman"+regKey;
    }

    @Path("securityQuestion")
    @POST
    public void postSecurityAnswer(String answer) {
        if(!answer.equals("iamahuman"+regKey)){
            throw new WebApplicationException(Status.BAD_REQUEST);
        }

        //Getting this information works properly
        List<RegistrationEntity> result = em.createNamedQuery("getRegistrationByKey")
            .setParameter("regKey", regKey).getResultList();

        switch(result.size()){
            case 0 :
                throw new WebApplicationException(Status.NOT_FOUND);
            case 1:
                break;
            default:
                throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR);
            }

            RegistrationEntity reg = result.get(0);
            UserEntity newUser = new UserEntity();

            newUser.setHashedPassword(reg.getPwHash(), reg.getSalt());
            newUser.setUsername(reg.getUsername());
            newUser.setName(reg.getName());
            newUser.setSurname(reg.getSurname());

            //CRASHES HERE
            em.persist(newUser);
    }
}

如您所见,它从数据库中获取注册对象,创建新用户进行注册并尝试将其持久化。但是,em.persist(newUser) 会抛出 TransactionRequiredException。

我的问题是:我应该如何将 EntityManager 传递给子资源,以便它可以正确地保留新对象?

【问题讨论】:

标签: java rest jpa jax-rs


【解决方案1】:

很抱歉再次挖掘这个问题,但我建议如下:

  • 还将子资源注释为@Stateless EJB
  • 将@EJB 注入成员字段放入父资源类中,如下所示: @EJB 私有 RegistrationResource 注册资源;
  • 在“getRegistrationResource()”中,不调用子资源的构造函数,而是返回注入的EJB引用:
    公共注册资源 getRegistrationResource() {
        返回 this.registrationResource;
    }

但是,要使其正常工作,您不能将“@PathParam”作为构造函数参数传递。您必须通过“@Context”或另一个@Path 声明在子资源中单独访问它。
这使您能够以与父资源中完全相同的方式将 EntityManager 注入子资源中,您不需要传递它。

【讨论】:

    【解决方案2】:

    可能为时已晚,但无论如何...... 当您返回子资源时,您将“离开”无状态 bean。由于容器管理事务,因此在您从 RegistrationsResource 返回时提交事务。

    然后,Jersey 将构建您的子资源,但它不是无状态 bean,因此您不会有容器管理的事务。因此例外。

    我建议您将业务逻辑放在一个新类中,然后您将创建一个无状态 bean。在这里,您完成所有数据库工作,然后始终在容器管理的事务中处理这些工作。

    【讨论】:

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