JPA事务:提交后立即选择?

时间:2013-10-01 02:10:20

标签: java jpa jboss ejb

我正在使用带有EJB / JPA的JBoss EAP 6.1.0。我有一个User对象,他有几个他所属的组,我正在尝试使用三步法在数据库中创建它:

  1. 保存用户
  2. 保存他所属的群组
  3. 查询数据库并返回该新用户
  4. 我的问题是步骤(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()会创建一个嵌套事务,它不应该知道保存了吗?

2 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:0)

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