2012-02-03 90 views
5

我有一个Seam 3沙箱应用程序,它使用JBoss 7,Hibernate作为默认的JPA实现,JSF作为Web前端。JPA/Hibernate在EJB/Seam环境下不提交UPDATE提交更新

我有问题,SQL UPDATE被默认吞下。

我在谈话范围状态EJB维持一个扩展范围的EntityManager的和一个实体,容器管理事务(需要新)

  1. 实体管理器被注入
  2. 的EJB使用EM加载实体并保持它在一个场
  3. JSF应用访问EJB及其实体,改变字符串字段中EJB
  4. JSF应用卡列斯“保存”方法
  5. 在保存()我检查,如果实体字段已更改 - >它已被正确更改
  6. 我什么也没做,容器在save()完成后提交事务。
  7. 问题:没有对数据库执行SQL更新。

如果我延伸保存()由:

a)按预期执行UPDATE entityManager.contains(实体)(结果为 “真”)

OR

b)中entityManager.persist(entity)UPDATE按预期方式执行

问:据我了解规范不应该要求a)或b),因为实体在整个过程中保持管理状态。 我不明白,为什么a)对储蓄有影响。 我可以成像b)对储存有影响,但它不应该是必需的,应该吗?

欢迎任何解释。

这里是我的EJB:

@Named 
@ConversationScoped 
@Stateful 
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) 
public class LanguageBean { 

    @PersistenceContext(type = PersistenceContextType.EXTENDED) 
    private EntityManager em; 
    @Inject 
    private UserTransaction transaction; 

    private Language value; 

    @Inject 
    Conversation conversation; 

    public LanguageBean() { 
     super(); 
    } 

    @Begin 
    public void selectLanguage(Long anId) { 
     conversation.setTimeout(10 * 60 * 1000); 
     if (anId != null) { 
      value = em.find(Language.class, anId); 
     } 
    } 

    @BeforeCompletion 
    public void transactionComplete(){ 
     System.out.println("transactionComplete"); 
    } 

    public Language getValue() { 
     return value; 
    } 

    @Produces 
    @Named 
    @ConversationScoped 
    public Language getLanguage() { 
     return getValue(); 
    } 

    public void setValue(Language aValue) { 
     value = aValue; 
    } 

    @End 
    public String save() { 
//  displays the changed attribute: 
     System.out.println("save code: "+value.getCode()); 

//  why is either this required: 
//  boolean tempContains = em.contains(value); 
//  System.out.println("managed: "+tempContains); 

//  or: why is persist required: 
     em.persist(value); 
     return "languages?faces-redirect=true"; 
    } 

    @End 
    public String cancel() throws SystemException { 
     transaction.setRollbackOnly(); 
     return "languages?faces-redirect=true"; 
    } 

} 
+0

我发现entityManager.flush ()也解决了这个问题。但我不明白为什么这似乎是必需的。根据JPA规范:“当JTA事务提交时,提供者必须将所有修改后的实体状态刷新到 数据库。” – user1187037 2012-02-03 08:52:08

+0

也许某处休眠会话的FlushMode设置为none? – Firo 2012-02-06 11:40:20

回答

0

尝试通过@End注解的方法添加注释@Remove

在我看来@End注释不会导致bean破坏。所以即使执行save()并且其内容无法刷新到数据库,持久化上下文仍处于活动状态。

1

我的经验主要是缝2,但在这里应该同样适用。

对话和JPA会话在接缝中解耦,原因很简单,即会话结束可能不会导致实体被保存。

例如,在长时间运行的对话取消行动将结束谈话(因为没有理由再保持通话)

考虑到你是在你的榜样取消执行回滚,它似乎也合乎逻辑,您需要按照@ user1187037的建议调用flush(理论上是提交,但我认为不允许)

我认为可能有一个配置可以设置,谈话结束,但我可能会误解。

在任何情况下,http://javalangblog.blogspot.co.uk/2010/04/flush-mode-conversation.html似乎提出一个解决方案

希望有所帮助。

编辑:您可以使用XML

<begin-conversation join="true" flush-mode="COMMIT" /> 

和使用注释

@Begin(flushMode=COMMIT) 

配置每个对话的刷新模式。请记住,虽然对话可以没有它被明确定义@End。如果用户在通话过程中,对实体进行了更改,然后放弃对话,则会在超时后自动关闭。如果我没有记错,这将导致在上述情况下发生任何更改。

参考文献:

http://docs.jboss.org/seam/3/persistence/3.0.0.Alpha1/reference/en-US/html_single/#d0e249 http://docs.jboss.org/seam/3/latest/api/org/jboss/seam/persistence/FlushModeType.html