【问题标题】:JPA and EJB managed vs. non-managedJPA 和 EJB 托管与非托管
【发布时间】:2016-02-11 00:53:50
【问题描述】:

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

我有一个UserService,它是一个EJB

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

我遇到了一些问题并进行了一些调试,发现有时在hasRole 中,User 不处于托管状态,为什么我这样做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 处于非托管状态。但为什么?!

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

【问题讨论】:

    标签: jakarta-ee jpa ejb entity managed


    【解决方案1】:

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

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

    当您将相同的非托管实体传递回服务层时,它仍然是非托管的,直到您对其调用 em.merge(),或者通过em.find() 从 DB 获取一个新的实体 @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)不需要从单个操作方法连续调用多个不同的方法。相反,重构和/或将多个不同服务方法的特定序列合并到单个服务方法中。这保证了作业将在单个事务中进行。

    另见:

    【讨论】:

    • 但是方法呢,hasRole(User, RoleType) 或 updateRole(User, RoleType)。在这里我总是要调用 find() 或 merge(),对吗?
    • 在 hasRole 中,只有当关系被延迟加载并且父实体是在不同的事务中获得时才需要(因此,如果急切地获取它就没有必要)。在 updateRole 中,这是不必要的,因为您最终已经使用 em.merge() 对其进行了管理,因此所有更改都将在服务方法返回时保留。
    猜你喜欢
    • 2011-11-18
    • 1970-01-01
    • 2019-07-14
    • 1970-01-01
    • 2011-10-01
    • 2015-07-26
    • 2013-02-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多