5

我有一个使用 JBoss 7 的 Seam 3 沙盒应用程序,Hibernate 作为默认 JPA 实现,JSF 作为 Web 前端。

我有一个问题,默认情况下 SQL UPDATE 被吞下。

我在对话范围内的有状态 EJB 维护一个扩展范围的 EntityManager 和一个实体、容器管理事务(需要新的)

  1. EntityManager 被注入
  2. EJB 使用 EM 加载实体并将其保存在字段中
  3. JSF 应用程序访问 EJB 及其实体,更改字符串字段
  4. JSF 应用程序在 EJB 中调用“保存”方法
  5. 在 save() 中,我检查实体字段是否已更改 -> 是否已正确更改
  6. 我什么也不做,容器在 save() 完成后提交事务。
  7. 问题:没有对数据库执行 SQL 更新。

如果我通过以下方式扩展 save():

a) entityManager.contains(entity) UPDATE 按预期执行(结果为“true”)

或者

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";
    }

}
4

2 回答 2

1

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

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

例如,对长时间运行的对话执行取消操作会结束对话(因为没有理由再维持对话了)

考虑到您正在对示例中的取消进行回滚,您需要按照@user1187037 的建议调用刷新似乎也是合乎逻辑的(理论上是提交,但我认为这是不允许的)

我认为您可能可以设置一个配置,以便它在对话结束时刷新,但我可能弄错了。

无论如何,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

于 2012-10-17T23:08:23.560 回答
0

尝试在由 .@Remove注释的方法上添加注释@End

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

于 2012-03-16T10:39:56.547 回答