2012-03-15 4 views
5

Я получаю ERROR: duplicate key value violates unique constraint "users_pkey" Detail: Key (userid)=(2701) already exists. всякий раз, когда я использую модель persist для обновления моего пользовательского объекта.Обновление Entity с использованием EntityManager JPA EclipseLink

В приведенном ниже примере кода SetLoginAttempts принимает пользовательский объект, который был запрошен, и когда я начинаю транзакцию, я просто устанавливаю одно из полей сущности и вызываю 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(); 

При взгляде на трассировки стека, я заметил, что фиксация фактически вводит вставку

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] 

Что правильный способ ссылаться на диспетчер объектов в Spring roo, обновлять поле и фиксировать изменения?

Редактировать

Я добавил @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 [[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 

Но до сих пор нет обновления БД даже после обновления , почему не происходит закрытие транзакции и обновление БД?

ответ

16

JPA предоставляет два метода ... сохраняется() и слияние()

Persist: Persist несет ответственность за вставки новых строк в БД, а затем связывая Entity с состоянием в JPA сессии.

Merge: Merge принимает существующий объект и обновляет строку DB. Он также обновляет состояние объекта в сессии JPA.

Я думаю, что пользователь уже существует в вашей таблице базы данных. Чтобы обновить количество логинов, вы можете использовать метод merge() на EntityManager.

+0

Я просто попытался заменить упорствовать() со слиянием() и кажется, что ничего не произошло. Еще раз взглянув на трассировку стека, и почему-то я получил сообщение «Инициировать откат транзакции» по какой-то причине? как я могу предотвратить его откат, чтобы я мог видеть изменения в БД – Warz

+0

Записать следующий внутренний класс: '@PersistenceContext (unitName =" myEntityManager ") private EntityManager entityMgr; public void setLoginAttempts (Пользователь user, int попыткаNumber) { user.setLoginAttempts (попыткаNumber); entityMgr.merge (пользователь); } public User getUser (Object userId) { return entityMgr.find (User.class, userId); } ' – Ameya

0

EntityManager.persist() используется для создания нового компонента сущности.

Создание нового компонента сущности включает в себя вставку новой строки в базу данных.

Вы используете EntityManager.merge() для обновления существующего компонента, который уже существует.

Вызов EntityManager.merge() обновляет базу данных, чтобы отразить изменения, внесенные в отсоединенный объект.

Если ваш объект bean не отсоединен, нет необходимости ссылаться на merge().

Если пользовательский компонент не отключен, вы можете просто изменить его свойства, вызвав методы, подобные setLoginAttempts().

EntityManager и контейнер автоматически обновляют базу данных (при совершении транзакции).

+0

Если я просто вызываю setLoginAttempts(), не приобретая EntityManager, вызывая persist() или merge(), журналы показывают (с оператором печати), что поле обновлено. Однако обновление базы данных или закрытие приложения не отражают сделанные изменения? – Warz

+0

Я бы рекомендовал разрешить контейнеру обрабатывать транзакцию (вместо того, чтобы делать это самостоятельно). Предполагая, что вы используете EJB 3, вы можете просто аннотировать метод с помощью соответствующего TransactionAttribute, и контейнер будет выполнять грязную работу. На самом деле, тип TransactionAttributeType по умолчанию НЕОБХОДИМО, что автоматически обертывает весь метод в транзакции. – jahroy

+0

Проверьте это: http://openejb.apache.org/transaction-annotations.html – jahroy

2

Если ни один из указанных работ, попробуйте (путем корректировки, поскольку она имеет отношение к моему коду):

  Query query = entityManager.createQuery("UPDATE User x SET x.activated = 1 "+ "WHERE username=:usernameParam "); 
      query.setParameter("usernameParam", ""+user.username); 
      query.executeUpdate(); 
Смежные вопросы