JPA/Hibernate 在 EJB/Seam 环境中提交时不发出更新
我有一个 Seam 3 沙箱应用程序,使用 JBoss 7、Hibernate 作为默认 JPA 实现,并使用 JSF 作为 Web 前端。
我有一个问题,默认情况下 SQL UPDATE 被吞没。
我的状态 EJB 在会话范围内维护一个扩展范围的 EntityManager 和一个实体,容器管理事务(需要新的)
- EntityManager 被注入
- EJB 使用 EM 加载实体并将其保存在一个字段中
- JSF 应用程序访问 EJB 及其实体,更改字符串字段
- JSF 应用程序在 EJB 中调用“Save”方法
- 在 save() 中,我检查实体字段是否已更改 ->它已正确更改
- 我什么也不做,容器在 save() 完成后提交事务。
- 问题:未对数据库执行 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";
}
}
I have a Seam 3 sandbox application using JBoss 7, Hibernate as default JPA implementation and as JSF as web front end.
I have the problem, that the SQL UPDATE is swallowed by default.
My stateful EJB in conversation scope maintains an extended scoped EntityManager and one Entity, Container Managed Transactions (Requires new)
- The EntityManager gets injected
- The EJB uses the EM to load the Entity and keeps it in a field
- JSF application accesses the EJB and its entity, changes a String field
- JSF application calles "Save" method in EJB
- In save() I check, if the Entities field was changed -> it was changed properly
- I do nothing more, the container commits the transaction after save() is finished.
- Problem: No SQL update is performed against the DB.
If i extend save() by:
a) entityManager.contains(entity) the UPDATE is executed as expected (result is "true")
OR
b) entityManager.persist(entity) the UPDATE is executed as expected
Q: As far as I understand the specs neither of a) or b) should be required, because the Entity remains managed during the entire process.
I dont understand, why a) has an effect on saving.
I can imaging the b) has an effect on saving, but it should not be required, should it?
Any explanation is welcome.
Here is my 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";
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我的经验主要是关于seam-2,但应该同样适用于这里。
会话和 JPA 会话是解耦的,原因很简单,会话结束可能不会导致实体被保存。
例如,对长时间运行的对话执行取消操作将结束对话(因为没有理由再维持对话)
考虑到您在示例中对取消进行回滚,您需要按照@user1187037的建议调用刷新(理论上是一个提交,但我认为这是不允许的)
我认为您可能可以设置一个配置,以便它在对话结束时刷新,但我可能是错的。
无论如何, http://javalangblog.blogspot.co.uk /2010/04/flush-mode-conversation.html 似乎提出了一个解决方案
希望有帮助。
来配置每个会话的刷新模式,
编辑:您可以使用 xml和使用注释
但请记住,会话可以 @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
My experience is largely with seam-2 but should be equally applicable here.
The conversation and JPA session is decoupled in seam for the simple reason that a conversation ending may not result in the entity being saved.
For example, a cancel action on a long running conversation would end the conversation (since there is no reason to maintain the conversation anymore)
Considering that you are doing a rollback on the cancel in your example, it would also seem logical that you would need to call a flush as suggested by @user1187037 (theoretically a commit but I don't think that's allowed)
I think there might have been a configuration you could set so that it did flush on conversation end but I may be mistaken.
In any case, http://javalangblog.blogspot.co.uk/2010/04/flush-mode-conversation.html seems to suggest a solution
Hope that helps.
EDIT: You can configure the flush mode per conversation using xml
and using annotations
Bear in mind though that a conversation can @End without it being explicitly defined. If a user is partway through the conversation, made changes to entities and then abandons the conversation, it will get automatically closed after a timeout. If I remember correctly, this will cause any changes to get committed in the above case.
References:
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
尝试在
@End
注释的方法上添加@Remove
注释。在我看来,@End 注释不会导致 bean 破坏。因此,即使在
save()
执行之后,持久性上下文仍然处于活动状态,并且其内容无法刷新到数据库。Try to add
@Remove
annotation on methods annotated by@End
.In my opinion
@End
annotation does not result in bean destruction. So the persistence context is active even aftersave()
execution and its content cannot be flushed to database.