2013-10-01 42 views
1

我正在使用JBoss EAP 6.1.0和EJB/JPA。我有几个组的用户对象,他是属于我试图用三步法在数据库中创建此:JPA事务:提交后选择正确?

  1. 保存用户
  2. 保存他属于
  3. 查询组数据库并返回新的用户

我的问题是,步骤(3)总是返回null,因为提交尚未发生。在步骤2和步骤3之间添加em.flush()不会有帮助。我避免使用任何@CASCADE批注,因此只保存用户并让群组级联不是一个选项。下面是示例代码:

@Stateless 
public class RegistrationService { 

    @EJB 
    UserDao userDao; 

    public User registerNewUser(User user, List<Group> groups) { 
     userDao.saveNewUser(user); 
     userDao.saveNewGroupsToUser(user, groups); 
     return userDao.findUser(user); 
    } 
} 

这里是一个简化的UserDAO:

@Stateless 
public class UserDao { 

    @PersistenceContext 
    private EntityManager em; 

    public void saveNewUser(User user) { 
    em.persist(user); 
    } 

    public void saveNewGroupsToUser(User user, List<Group> groups) { 
    for (Group group : groups) { 
     GroupToUser groupToUser = new GroupToUser(user, group); 
     em.persist(groupToUser); 
    } 

    public User findUser(User user) { 
    return em.createQuery("from User where user = :userId") 
     .setParameter("userId",user.getUserId()) 
     .getSingleResult(); 
    } 
} 

什么我发现是,如果我注释findUser(User)方法与@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)它按预期工作。这是为什么呢?我认为registerNewUser()创建了一个大事务,然后findUser()会创建一个嵌套的事务,它不应该知道有关的存储呢?

回答

0

我最终在findUser()方法上使用了@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)。由于容器管理事务(CMT)不允许嵌套事务,因此这似乎会刷新先前的SQL更新/插入语句,从而允许select按预期工作。

2

我想你应该在步骤1(保存用户之后)后添加em.flush(),因为它将执行保存新用户的SQL。

第二件事,从代码看来,使用容器管理的事务。 CMT不允许嵌套事务。所以基本上添加REUIRED_NEW属性可能会强制刷新以前的保存SQL查询。确认这一点的一种方法是记录SQL查询

+0

保存后的em.flush()似乎没有效果,我仍然回到空。我会继续调查。 – Strumbles

+0

我想我会坚持使用'findTransactionAttribute(TransactionAttributeType.REQUIRES_NEW)'在'findUser()'方法,因为这样做的窍门。由于我使用CMT,这可能是我能得到的最好的。 – Strumbles