我将Java 8
与Spring 4.3.1.RELEASE
和Hibernate 5.2.1.Final
以及JPA
与MySQL
一起使用。
我在数据库中有一行:
PERSON TABLE
# ID, UID, JOINING_DATE, LASTACCESS_DATE, DISPLAY_NAME, EMAIL_ADDRESS, AVATAR, PROVIDER, AVATAR_FIREBASE, MILES_KM, NOTIFICATIONS, CONTACTABLE, DEVICE_TOKEN
'384', 'h6qQg5YfQveTaCyBEXwDMSJPqwk1', '1499148701258', '1499240111170', 'Richard', 'richardmarais@gmail.com', ?, '3', 'https://scontent.xx.fbcdn.net/v/t1.0-1/p100x100/14484731_10155363658503146_8505143722410369457_n.jpg?oh=3b6fbb0facc9457f7e8387e4853278a8&oe=59D6034D', '0', '1', NULL, 'e_6U3WAVHu0:APA91bFibmAaVTLO13vG1Aww0yLK2UzRNopLK1UalurfYRXcCbUDrTJQKOm0hiKkyxV1auEWTL9od5ek62FfJIzo1li6vrgA6CfxE6Cu2HnPkSPGaeFispI2c16UBZcLZfYGRe1i9nmf'
当我尝试将Hibernate用于merge
具有现有行的对象时,它会抛出一个错误,表明它是重复的。我想因为我正在做merge
,它会更新现有的行。
我有以下代码:
PersonServiceImpl.java
@Transactional
public class PersonServiceImpl implements PersonService {
@Override
public Person save(Person person) throws Exception {
try {
person = personDao.merge(person);
调用:
PersonDaoImpl.java
public class PersonDaoImpl extends JpaDao<Long, Person> implements PersonDao
@Override
public Person merge(Person person) throws InstantiationException, IllegalAccessException {
Person foundPerson = null;
if (!StringUtils.isEmpty(person.getUid())) {
foundPerson = findByUid(person.getUid(), person.getProvider());
}
if (foundPerson == null && !StringUtils.isEmpty(person.getId())) {
foundPerson = findById(person.getId());
}
if ((foundPerson == null || foundPerson.getUid() == null) && person.getEmailAddress() != null) {
foundPerson = findByEmail(person.getEmailAddress());
if (foundPerson != null) {
foundPerson.setUid(person.getUid());
}
}
if (foundPerson != null && person.getUid().equals(foundPerson.getUid())) {
if (person.getLocations().isEmpty() && foundPerson.getLocations() != null && !foundPerson.getLocations().isEmpty()) {
person.setLocations(foundPerson.getLocations());
}
BeanUtils.copyProperties(person, foundPerson);
if (foundPerson.getLocations().isEmpty() && person.getLocations() != null && !person.getLocations().isEmpty()) {
foundPerson.setLocations(person.getLocations());
}
foundPerson.setLastAccessDate(System.currentTimeMillis());
if (Objects.isNull(foundPerson.getJoiningDate()) || foundPerson.getJoiningDate() == 0) {
foundPerson.setJoiningDate(System.currentTimeMillis());
}
return super.merge(foundPerson); // << line executed
} else {
return super.merge(person);
}
}
调用:
JpaDao.java
public class JpaDao<I, T extends AbstractDomain<I>> {
protected Class<T> entityClass;
protected T merge(T entity) throws InstantiationException, IllegalAccessException {
T attached = null;
if (entity.getId() != null) {
attached = entityManager.find(entityClass, entity.getId()); // << line executed
}
if (attached == null) {
attached = entityClass.newInstance();
}
BeanUtils.copyProperties(entity, attached);
entityManager.setFlushMode(FlushModeType.COMMIT);
attached = entityManager.merge(attached);
return attached;
}
但是,当我尝试merge
Person
对象时,我收到以下错误:
错误
09:53:10,775 WARN [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (默认任务-33)SQL错误:1062,SQLState:23000 09:53:10,781错误 [org.hibernate.engine.jdbc.spi.SqlExceptionHelper](默认任务-33) 重复录入&#39; 384-8576&#39;关键&#39; PRIMARY&#39; 09:53:10,781 INFO [org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl](默认 task-33)HHH000010:在批量发布时它仍然包含JDBC 陈述09:53:10,782错误 [org.hibernate.internal.ExceptionMapperStandardImpl](默认任务-33) HHH000346:托管刷新期间出错 [org.hibernate.exception.ConstraintViolationException:不能 执行声明]
问题
如果行存在,我将如何实现代码以允许更新?
谢谢
更多信息
以下是Entity
:
Person.java
@Entity
@Table(name = "person")
@XmlRootElement(name = "person")
public class Person extends AbstractDomain<Long> {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Size(min = 1, max = 45)
@Column(name = "UID")
private String uid;
@Column(name = "JOINING_DATE", nullable = false)
private Long joiningDate;
@Column(name = "LASTACCESS_DATE", nullable = false)
private Long lastAccessDate;
@Size(min = 1, max = 85)
@Column(name = "DISPLAY_NAME", nullable = false)
private String displayName;
@Size(min = 5, max = 55)
@Column(name = "EMAIL_ADDRESS", nullable = false, unique = true)
private String emailAddress;
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinTable(name = "person_language", joinColumns = {
@JoinColumn(name = "PER_ID", referencedColumnName = "ID") }, inverseJoinColumns = {
@JoinColumn(name = "LANG_ID", referencedColumnName = "LANGUAGE_CODE", unique = true) })
private Set<Language> languages;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
@JoinTable(name = "person_location", joinColumns = {
@JoinColumn(name = "PER_ID", referencedColumnName = "ID") }, inverseJoinColumns = {
@JoinColumn(name = "LOC_ID", referencedColumnName = "ID", unique = true) })
private Set<LocationPerson> locations = null;
@Basic(fetch = FetchType.LAZY)
@Lob
@Column(name = "AVATAR", nullable = true)
private byte[] avatar;
@Column(name = "PROVIDER")
private Integer provider;
@Column(name = "AVATAR_FIREBASE")
private String avatarFirebase;
@Column(name = "MILES_KM")
private Integer milesKm;
@Column(name = "NOTIFICATIONS")
private Integer notifications;
@Size(max = 256)
@Column(name = "DEVICE_TOKEN")
private String deviceToken;
@XmlElement
public String getDeviceToken() {
return deviceToken;
}
public void setDeviceToken(String deviceToken) {
this.deviceToken = deviceToken;
}
@XmlElement
public Integer getMilesKm() {
return milesKm;
}
public void setMilesKm(Integer milesKm) {
this.milesKm = milesKm;
}
@Column(name = "CONTACTABLE")
private Long contactable;
@Transient
private Boolean contactableFree;
@XmlElement
public Boolean getContactableFree() {
return contactableFree;
}
public void setContactableFree(Boolean contactableFree) {
this.contactableFree = contactableFree;
}
@XmlElement
public Long getContactable() {
return contactable;
}
public void setContactable(Long contactable) {
this.contactable = contactable;
}
@XmlElement
public Integer getNotifications() {
return notifications;
}
public void setNotifications(Integer notifications) {
this.notifications = notifications;
}
@XmlElement
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@XmlElement
public Long getJoiningDate() {
return joiningDate;
}
public void setJoiningDate(Long joiningDate) {
this.joiningDate = joiningDate;
}
@XmlElement
public Long getLastAccessDate() {
return lastAccessDate;
}
public void setLastAccessDate(Long lastAccessDate) {
this.lastAccessDate = lastAccessDate;
}
@XmlElement
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
@XmlElement
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
@XmlElement
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
@XmlElement
public Set<Language> getLanguages() {
return languages;
}
public void setLanguages(Set<Language> languages) {
this.languages = languages;
}
@XmlElement
public Set<LocationPerson> getLocations() {
return locations;
}
public void setLocations(Set<LocationPerson> locations) {
if (this.locations == null) {
this.locations = locations;
} else {
this.locations.retainAll(locations);
this.locations.addAll(locations);
}
}
public void putLocations(Set<LocationPerson> locations) {
if (locations != null) {
this.locations.clear();
this.locations.addAll(locations);
} else {
this.locations = locations;
}
}
@XmlElement
public byte[] getAvatar() {
return avatar;
}
public void setAvatar(byte[] avatar) {
this.avatar = avatar;
}
@XmlElement
public Integer getProvider() {
return provider;
}
public void setProvider(Integer provider) {
this.provider = provider;
}
@XmlElement
public String getAvatarFirebase() {
return avatarFirebase;
}
public void setAvatarFirebase(String avatarFirebase) {
this.avatarFirebase = avatarFirebase;
}
}
更新
在阅读the following后,我将Person
对象locations
从CascadeType.ALL
更改为CascadeType.PERSIST
。
Person.java
@OneToMany(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER, orphanRemoval = true)
@JoinTable(name = "person_location", joinColumns = {
@JoinColumn(name = "PER_ID", referencedColumnName = "ID") }, inverseJoinColumns = {
@JoinColumn(name = "LOC_ID", referencedColumnName = "ID", unique = true) })
private Set<LocationPerson> locations = null;
更新已完成到数据库,但我现在得到以下内容:
10:41:20,657错误 [org.hibernate.internal.ExceptionMapperStandardImpl](默认任务-7) HHH000346:托管刷新期间出错 [org.hibernate.TransientObjectException:object引用未保存的 瞬态实例 - 在查询刷新之前保存瞬态实例: com.jobs.spring.domain.LocationPerson] 10:41:21,429 INFO [org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl](默认 task-7)HHH000010:在批量发布时,它仍然包含JDBC 语句