JPA和EJB管理与非托管

时间:2015-11-10 07:43:39

标签: java-ee jpa ejb entity managed

我有点困惑:我有一个带有JSF,EJB和JPA的Java EE应用程序。

我的UserServiceEJB

@Stateless
public class UserService {
    public User create(User u) throws ProcessingException {
        if (!exists(u)) {
            u = userDao.create(u);
            addRole(u, RoleType.USER);
            return u;
        } else {
            throw new ProcessingException("User " + u.getUsername() + " already exists");
        }
    }   


    public boolean hasRole(User u, RoleType r) {
        if (u == null || r == null) {
            return false;
        }

        if (!userDao.isManaged(u)) {
            u = userDao.find(u.getId());
        }

        Set<Role> roles = u.getRoles();
        ...
    }
}

我遇到了一些问题,并进行了一些调试,发现有时在hasRoleUser不在托管状态,为什么我userDao.isManaged(u)。但是,我无法理解为什么它有时不被管理。你能解释一下原因吗?

示例:

@Test
public void test() throws ProcessingException {
    Client c = clientBuilder.build();
    User u = new User();
    u.setClient(c);
    userService.create(u);

    userService.addRole(u, RoleType.APPROVER);

调用addRole(u, RoleType.APPROVER)时,u状态为非托管状态。但为什么?!

我是否总是必须在我的方法中添加检查以确保实体是受管理的?

1 个答案:

答案 0 :(得分:4)

实体仅在与从DB获得的事务相同的事务中进行管理。

@Stateless EJB中,来自客户端的单个方法调用默认计为单个完整事务。所有嵌套的EJB方法调用都在同一事务中进行。但是一旦从客户端调用EJB方法返回到客户端(例如,JSF / CDI托管bean),事务就结束了。当该方法返回一个实体时,它就会变得不受管理。

当您将同一个非托管实体传回服务层时,它仍然无法管理,直到您在其上调用em.merge(),或者em.find() @Id从数据库获取一个新的实体}。

在您的具体情况下,您可以更改create()服务方法,如下所示:

public User create(User user, RoleType... roles) {
    // ...

    for (RoleType role : roles) {
        addRole(user, role);
    }

    return user;
}

所以你可以在一次交易中执行这项工作

userService.create(u, RoleType.APPROVER);

而不是两次交易

userService.create(u);
userService.addRole(u, RoleType.APPROVER);

EJB方法的设计应该使客户端(JSF / CDI托管bean)不需要从单个操作方法连续调用多个不同的方法。相反,将多个不同服务方法的这种特定序列重构和/或合并为单个服务方法。这可以保证作业将在单个交易中进行。

另见: