Java 使用EntityManager JPA EclipseLink更新实体

Java 使用EntityManager JPA EclipseLink更新实体,java,jpa,eclipselink,spring-roo,Java,Jpa,Eclipselink,Spring Roo,我收到一个错误:重复的键值违反了唯一约束“users\u pkey” 详细信息:Key(userid)=(2701)已存在。每当我使用persist模型更新我的用户实体时 在下面的代码示例中:setLoginAttents接收已查询的用户实体,当我启动事务时,我只需设置实体的一个字段并调用persist(),然后提交事务 /** * @param user * @param attemptNumber */ @Transactional public void setLoginAttempts(

我收到一个
错误:重复的键值违反了唯一约束“users\u pkey”
详细信息:Key(userid)=(2701)已存在。
每当我使用persist模型更新我的用户实体时

在下面的代码示例中:setLoginAttents接收已查询的用户实体,当我启动事务时,我只需设置实体的一个字段并调用persist(),然后提交事务

/**
* @param user
* @param attemptNumber
*/
@Transactional
public void setLoginAttempts(Users user, int attemptNumber){         
    user.setLoginAttempts(attemptNumber);
    System.out.println(user);
}
以下是我如何引用和获取实体管理器:

eFactory = Persistence.createEntityManagerFactory("persistenceUnit");
eManager = eFactory.createEntityManager();
在查看堆栈跟踪时,我注意到commit实际上插入了一个insert

Call: INSERT INTO USERS (userID, EMAIL, ISLOCKED, LOGINATTEMPTS, passwordHash, passwordSalt, USERNAME, version) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
bind => [2701, admin@d.com, false, 1, $shiro1$SHA-256$500000$6mqzZ/d/3BLQuJqLh1dDhQ==$NKW7Z++o/JTvf884aDWhP3Uhpyb5fTPMrm4joWnw7nI=, [B@1a8e3115, admin, 1]
在SpringRoo中引用实体管理器、更新字段和提交更改的正确方法是什么

编辑

我将@Transactional添加到方法中,堆栈跟踪显示这正在创建实体管理器实例:

2012-03-14 23:49:15,503 ["http-bio-8080"-exec-18] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Creating new transaction with name [org.bixin.dugsi.service.UserService.setLoginAttempts]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2012-03-14 23:49:15,503 ["http-bio-8080"-exec-18] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Opened new EntityManager [org.eclipse.persistence.internal.jpa.EntityManagerImpl@46b9979b] for JPA transaction
[EL Finer]: 2012-03-14 23:49:15.503--ServerSession(2128384958)--Thread(Thread["http-bio-8080"-exec-18,5,main])--client acquired: 1116759395
[EL Finer]: 2012-03-14 23:49:15.503--ClientSession(1116759395)--Thread(Thread["http-bio-8080"-exec-18,5,main])--acquire unit of work: 368076985
2012-03-14 23:49:15,503 ["http-bio-8080"-exec-18] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Not exposing JPA transaction [org.eclipse.persistence.internal.jpa.EntityManagerImpl@46b9979b] as JDBC transaction because JpaDialect [org.springframework.orm.jpa.DefaultJpaDialect@c595bcd] does not support JDBC Connection retrieval
Email: admin@d.com, Id: 2701, IsLocked: false, LoginAttempts: 2, Password: $shiro1$SHA-256$500000$6mqzZ/d/3BLQuJqLh1dDhQ==$NKW7Z++o/JTvf884aDWhP3Uhpyb5fTPMrm4joWnw7nI=, PasswordSalt: [B@1a8e3115, Roles: 0, Username: admin, Version: null
2012-03-14 23:49:15,503 ["http-bio-8080"-exec-18] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Initiating transaction commit
2012-03-14 23:49:15,503 ["http-bio-8080"-exec-18] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Committing JPA transaction on EntityManager [org.eclipse.persistence.internal.jpa.EntityManagerImpl@46b9979b]
[EL Finer]: 2012-03-14 23:49:15.503--UnitOfWork(368076985)--Thread(Thread["http-bio-8080"-exec-18,5,main])--begin unit of work commit
[EL Finer]: 2012-03-14 23:49:15.503--UnitOfWork(368076985)--Thread(Thread["http-bio-8080"-exec-18,5,main])--end unit of work commit
[EL Finer]: 2012-03-14 23:49:15.504--UnitOfWork(368076985)--Thread(Thread["http-bio-8080"-exec-18,5,main])--resume unit of work
2012-03-14 23:49:15,504 ["http-bio-8080"-exec-18] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Closing JPA EntityManager [org.eclipse.persistence.internal.jpa.EntityManagerImpl@46b9979b] after transaction
2012-03-14 23:49:15,504 ["http-bio-8080"-exec-18] DEBUG org.springframework.orm.jpa.EntityManagerFactoryUtils - Closing JPA EntityManager
[EL Finer]: 2012-03-14 23:49:15.504--UnitOfWork(368076985)--Thread(Thread["http-bio-8080"-exec-18,5,main])--release unit of work

但即使在刷新之后,数据库仍然没有更新,为什么事务不关闭并更新数据库?

JPA公开了两种方法。。。persist()和merge()

Persist:Persist负责向数据库插入新行,然后将实体与JPA会话中的状态关联起来

合并:合并获取现有实体并更新数据库行。它还更新JPA会话中实体的状态

我认为您的数据库表中已经存在该用户。为了更新登录计数,可以在EntityManager上使用
merge()
方法。

()用于创建新的实体bean

创建一个新的实体bean需要在数据库中插入一个新行

您可以使用()来更新已经存在的实体bean

调用EntityManager.merge()更新数据库以反映对分离的实体bean所做的更改

如果实体bean未分离,则无需调用merge()。

如果您的用户bean没有分离,您可以通过调用setLoginAttents()之类的方法简单地修改它的属性


EntityManager和容器将自动更新数据库(当事务提交时)。

如果上述两项都不起作用,请尝试(通过调整,因为它与我的代码相关):


我刚刚尝试用merge()替换persist(),但似乎什么也没发生。再次查看堆栈跟踪,我会因为某种原因得到“启动事务回滚”?如何防止它回滚,以便在类内看到DBWrite中的更改:`@PersistenceContext(unitName=“myEntityManager”)private-EntityManager-entityMgr;public void setLoginAttents(Users user,int attemptNumber){user.setLoginAttents(attemptNumber);entityMgr.merge(user);}public user getUser(Object userId){return entityMgr.find(user.class,userId);}`如果我只调用setLoginAttents(),而不获取EntityManager,调用persist()或merge(),日志会显示(使用打印语句)字段已更新,但是刷新数据库或关闭应用程序并不能反映所做的更改?我建议让容器处理事务(而不是自己处理)。假设您使用的是EJB3,您只需使用适当的TransactionAttribute对该方法进行注释,容器就可以完成不必要的工作。实际上,默认的TransactionAttribute类型是必需的,它将自动将整个方法包装到事务中。我从查询中找到了调用该方法的用户(特别是spring roo中的finder方法),然后我想设置对该用户的尝试。据我所知,由于我从查询中读取了该用户,并且仍然使用该用户,所以我不需要创建或获取实体管理器实例,只需调用该实体上的set方法即可?
            Query query = entityManager.createQuery("UPDATE User x SET x.activated = 1 "+ "WHERE username=:usernameParam ");
            query.setParameter("usernameParam", ""+user.username);
            query.executeUpdate();