2012-03-15 21 views
5

Obtengo un ERROR: duplicate key value violates unique constraint "users_pkey" Detail: Key (userid)=(2701) already exists. cada vez que uso el modelo persist para actualizar mi entidad de usuario.Entidad de actualización utilizando EntityManager JPA EclipseLink

En el ejemplo de código siguiente: SetLoginAttempts toma una entidad de usuario que ha sido consultada y cuando comienzo la transacción simplemente configuro uno de los campos de la entidad y llamo a persist(), luego confirmo la transacción.

/** 
* @param user 
* @param attemptNumber 
*/ 
@Transactional 
public void setLoginAttempts(Users user, int attemptNumber){   
    user.setLoginAttempts(attemptNumber); 
    System.out.println(user); 
} 

Aquí es cómo referencia y agarro el gestor de entidades:

eFactory = Persistence.createEntityManagerFactory("persistenceUnit"); 
eManager = eFactory.createEntityManager(); 

Al mirar el seguimiento de la pila, he notado que el commit realidad inyecta una inserción

Call: INSERT INTO USERS (userID, EMAIL, ISLOCKED, LOGINATTEMPTS, passwordHash, passwordSalt, USERNAME, version) VALUES (?, ?, ?, ?, ?, ?, ?, ?) 
bind => [2701, [email protected], false, 1, $shiro1$SHA-256$500000$6mqzZ/d/3BLQuJqLh1dDhQ==$NKW7Z++o/JTvf884aDWhP3Uhpyb5fTPMrm4joWnw7nI=, [[email protected], admin, 1] 

¿Cuál es la forma correcta de hacer referencia a un administrador de entidades en Spring roo, actualizar un campo y confirmar los cambios?

Editar

que añade el @Transactional al método y el seguimiento de la pila muestra que esto es la creación de la instancia del gestor de entidades:

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 [[email protected]] 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 [[email protected]] as JDBC transaction because JpaDialect [[email protected]] does not support JDBC Connection retrieval 
Email: [email protected], Id: 2701, IsLocked: false, LoginAttempts: 2, Password: $shiro1$SHA-256$500000$6mqzZ/d/3BLQuJqLh1dDhQ==$NKW7Z++o/JTvf884aDWhP3Uhpyb5fTPMrm4joWnw7nI=, PasswordSalt: [[email protected], 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 [[email protected]] 
[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 [[email protected]] 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 

Pero todavía no hay cambios a la base de datos incluso después de actualización , ¿por qué no está la transacción cerrando y actualizando el DB?

Respuesta

16

APP expone dos métodos ... persisten() y fusionar()

Persistir: Persistir es responsable de insertar nuevas filas a DB y luego asociar la Entidad con el estado de sesión de la APP.

Merge: Merge toma la entidad existente y actualiza la fila DB. También actualiza el estado de la entidad en la sesión de JPA.

Creo que el usuario ya existe en su tabla de base de datos. Para actualizar el número de inicio de sesión, puede usar el método merge() en EntityManager.

+0

he intentado reemplazar persisten() con merge() y parece que no pasó nada. Mirando el seguimiento de la pila de nuevo y me sale esto "Iniciando una transacción de retroceso" por alguna razón? ¿Cómo evito que retroceda para que pueda ver los cambios en el DB – Warz

+0

Escribir siguiente clase interna: '@PersistenceContext (unitName =" myEntityManager ") EntityManager privado entityMgr; public void setLoginAttempts (Usuario usuarios, int attemptNumber) { user.setLoginAttempts (attemptNumber); entityMgr.merge (usuario); } public User getUser (Object userId) { return entityMgr.find (User.class, userId); } ' – Ameya

0

EntityManager.persist() se utiliza para crear un nuevo bean de entidad.

Crear un nuevo bean de entidad implica insertar una nueva fila en la base de datos.

Utiliza EntityManager.merge() para actualizar un bean de entidad que ya existe.

Llamar a EntityManager.merge() actualiza la base de datos para reflejar los cambios realizados en un bean de entidad separado.

Si su entity bean no está separado, no hay necesidad de invocar merge().

Si el grano de usuario no se separa, sólo tiene que modificar sus propiedades mediante llamadas a métodos como setLoginAttempts().

EntityManager y el contenedor actualizarán la base de datos automáticamente (cuando se confirma la transacción).

+0

Si simplemente llamo a setLoginAttempts() sin adquirir un EntityManager, al llamar a persist() o fusionar() los registros muestran (con la instrucción de impresión) que el campo está actualizado. Sin embargo, refrescar la base de datos o cerrar la aplicación no reflejar los cambios realizados? – Warz

+0

Yo recomendaría dejar que el contenedor maneje la transacción (en lugar de hacerlo usted). Suponiendo que está utilizando EJB 3, simplemente puede anotar el método con el Atributo de transacción apropiado y el contenedor hará el trabajo sucio. En realidad, el valor predeterminado TransactionAttributeType es OBLIGATORIO, lo que automáticamente envolverá todo el método en una transacción. – jahroy

+0

Mira esto: http://openejb.apache.org/transaction-annotations.html – jahroy

2

Si ninguna de las obras mencionadas, pruebe (ajustando ya que es relevante para mi código):

  Query query = entityManager.createQuery("UPDATE User x SET x.activated = 1 "+ "WHERE username=:usernameParam "); 
      query.setParameter("usernameParam", ""+user.username); 
      query.executeUpdate(); 
Cuestiones relacionadas