如何使用jax-rs子资源定位器处理持久性上下文(EntityManager)



我在带有子资源定位器的应用程序中使用jax-rs rest式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传递给子资源,以便它可以正确地持久化新对象?

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

  • 还将子资源注释为@无状态EJB
  • 将@EJB注入成员字段放入父资源类中,如下所示:<>之前ejb私有注册资源之前
  • 在"getRegistrationResource()"中,不调用子资源的构造函数,而是返回注入的EJB引用:
    public RegistrationResource getRegistrationResource() {返回this.registrationResource;} 
但是,要使

工作,您不能将"@PathParam"作为构造函数参数传递。你必须通过"@Context"或另一个@Path声明在子资源中单独访问它。
这使得你可以像在父资源中一样在子资源中注入EntityManager,而不需要传递它。

可能太晚了,但无论如何…当你返回子资源时,你就"离开"了无状态bean。当容器管理事务时,事务将在您从RegistrationsResource返回时提交。

Jersey将构造你的子资源,但它不是一个无状态bean,所以你不会有一个容器管理的事务。因此出现了例外。

我建议你把你的业务逻辑放在一个新的类中,然后把它变成一个无状态bean。这里你做所有数据库的东西,然后总是在容器管理的事务中处理。

最新更新