我的项目是一个用seam-gen生成的WAR项目。它包含一个像这样的RESTEasy Web服务类(简化,只有相关部分):
@Scope(ScopeType.APPLICATION)
public abstract class RestService {
@In
protected EntityManager entityManager;
@GET
@POST
@Produces("application/json")
public Object proxy() {
// invokes various subclass methods
// based on request parameters
// and returns the result
}
// further method and logic
}
和
@Path("/my")
@Name("myRestService")
public class MyRestService extends RestService {
public Object login(/*...*/) {
User user = getUser(email);
// ...
Token token = user.getToken();
if (token != null) {
entityManager.remove(token);
}
token = new Token();
entityManager.persist(token);
user.setToken(token);
user.setLastlogin(new Date());
entityManager.persist(user);
// ...
}
private User getUser(String email) {
try {
return (User) entityManager
.createQuery("FROM User WHERE UPPER(email) = UPPER(:email)")
.setParameter("email", email)
.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
}
如果我通过Web浏览器调用login方法,它会找到正确的用户(基于get参数),为它实例化一个Token(我可以在Hibernate的STDOUT上看到数据库的下一个序列),但是persist()方法不会将令牌保存到数据库中,也不会将User对象的修改(令牌ID,上次登录日期)保存。
我已经用Google搜索了两天,这是我能想到的:
我的项目使用SEAM托管事务(components.xml):
<persistence:managed-persistence-context name="entityManager" auto-create="true"
persistence-unit-jndi-name="java:/MyEntityManagerFactory"/>
我的项目使用JTA进行事务处理(persistence.xml):
<persistence-unit name="MyProject" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider> ...
EntityManager.persist()不提交对数据库的更改,只是将更改排队到当前事务(?)
SEAM托管交易默认情况下与对话相关联
我尝试使用.flush(),抛出异常,说没有正在进行的事务。
我尝试使用.joinTransaction()和.getTransaction()。begin(),抛出另一个异常,说JTA EntityManager无法访问事务。
还试图在类上使用不同的范围类型,或者在我的login()方法上使用@Transactional注释,没有运气。
还尝试使用@PersistenceContext注释注入EntityManager,这导致了一个异常,即@PersistenceContext只能与会话bean一起使用。
还试图将我的班级标记为@Stateless,这导致我无法联系到我的服务(404)。
如何使用EntityManager将我的实体保留在RESTEasy服务中?
系统规格:
请注意,我对JavaEE / JBoss / SEAM完全没有经验。
任何评论都会有用!感谢。
答案 0 :(得分:1)
您正在分离托管字段:
entityManager.remove(token);
创建一个新的:
token = new Token();
但是在这里:
entityManager.persist(token);
Token与User有关系(我不知道那个关系是什么 - oneToMany,oneToOne,你是从用户级联,获取等),但只是在令牌上调用persist不会重新建立这种关系。 看看这里 http://www.objectdb.com/java/jpa/persistence/crud
答案 1 :(得分:0)
事务性注释在登录方法中很重要。这将确保事务拦截器在必要时创建事务。 (如果还没有交易)。找出是否应用拦截器的最简单方法是调试登录方法并检查堆栈。我不确定如何调用该课程,但我会在工作时立即更新这篇文章。 如果此拦截器不存在则意味着您没有使用seam事务。 components.xml的摘录未显示您这样做。
马丁
更新: 所以这是堆栈跟踪。如果你的堆栈中没有这个,那么请看一下TransactionInterceptor,你没有事务管理。
Daemon Thread [http-18081-1] (Suspended (breakpoint at line 170 in QueryHome))
QueryHome.getCandidatesCount() line: 170
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
Method.invoke(Object, Object...) line: 597
Reflections.invoke(Method, Object, Object...) line: 22
RootInvocationContext.proceed() line: 32
SeamInvocationContext.proceed() line: 56
RollbackInterceptor.aroundInvoke(InvocationContext) line: 28
SeamInvocationContext.proceed() line: 68
BijectionInterceptor.aroundInvoke(InvocationContext) line: 77
SeamInvocationContext.proceed() line: 68
ConversationInterceptor.aroundInvoke(InvocationContext) line: 65
SeamInvocationContext.proceed() line: 68
TransactionInterceptor$1.work() line: 97
TransactionInterceptor$1(Work<T>).workInTransaction() line: 61
TransactionInterceptor.aroundInvoke(InvocationContext) line: 91
SeamInvocationContext.proceed() line: 68
MethodContextInterceptor.aroundInvoke(InvocationContext) line: 44
SeamInvocationContext.proceed() line: 68
JavaBeanInterceptor(RootInterceptor).invoke(InvocationContext, EventType) line: 107
JavaBeanInterceptor.interceptInvocation(Method, Object[]) line: 185
JavaBeanInterceptor.invoke(Object, Method, Method, Object[]) line: 103