java - 在 save() 操作期间,休眠调用子实体的更新,而插入父实体
问题描述
TL;博士
对于第三张表OneToMany
之间的映射Note
和使用,无法保存实体。Tag
Note_tag
save()
Note
背景:
所以我在这个NoteApp(Github repo location)上工作,它保存了一个带有标题、描述、状态和标签(标签是一个字符串值)的注释。作为功能更新,我想为一个注释添加多个标签。为此,我使用 faily straigt forward @JoinTable
annotation 创建了一个 Tag 表和第三个 tag 和 note 关联表。此功能导致我在保存 Note 实体时遇到上述问题。
我在屏幕后面使用的内容:
Java 1.8, Hiberanate, SpringBoot
有关技术堆栈的更多详细信息,请点击此处
我已经有的工作:
Save()
Note
没有Tag
s。
我的 Note.java:
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name = "T_NOTE")
public class Note implements Serializable {
private static final long serialVersionUID = -9196483832589749249L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="ID")
private Integer id;
@Column(name="TITLE")
private String title;
@Column(name="DESCRIPTION")
private String description;
@Column(name = "LAST_UPDATED_DATE")
private Date lastUpdatedDate;
@Column(name="STATUS")
private String status;
@OneToMany(cascade = CascadeType.ALL)
@JoinTable(name = "T_NOTE_TAG", joinColumns = { @JoinColumn(name="NOTE_ID", referencedColumnName = "ID") }, inverseJoinColumns = {
@JoinColumn(name = "TAG_ID", referencedColumnName = "TAG_ID") })
private List<Tag> tags = new ArrayList<Tag>();
/** getters setters omitted for brevity**/
}
我的标签.java:
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "T_TAG")
public class Tag implements Serializable {
private static final long serialVersionUID = -2685158076345675196L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="TAG_ID")
private Integer tagId;
@Column(name="TAG_NAME")
private String tagName;
}
我的 NoteDto.java:
public class NoteDto {
private int id;
private String title;
private String description;
private List<TagDto> tags = new ArrayList<TagDto>();
private Date lastUpdatedDate;
private String status;
}
我的 TagDto.java:
public class TagDto {
private int tagId;
private String tagName;
}
我的表创建查询:
CREATE database if NOT EXISTS noteApp;
CREATE TABLE `T_NOTE` (
`id` int(11) unsigned NOT NULL auto_increment,
`description` varchar(20) NOT NULL DEFAULT '',
`header` varchar(20) NOT NULL,
`status` varchar(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `T_TAG` (
`tag_id` int unsigned not null auto_increment,
`tag_name` varchar(30) not null,
PRIMARY KEY(TAG_ID)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `T_NOTE_TAG` (
`note_tag_id` int unsigned not null auto_increment,
`note_id` int unsigned not null,
`tag_id` int unsigned not null,
CONSTRAINT note_tag_note foreign key (`note_id`) references T_NOTE(`id`),
CONSTRAINT note_tag_tag foreign key (`tag_id`) references T_TAG(`tag_id`),
CONSTRAINT note_tag_unique UNIQUE (`tag_id`, `note_id`),
PRIMARY KEY (`note_tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
use noteApp;
ALTER TABLE T_NOTE
Change header title varchar(1000) NOT NULL;
ALTER TABLE T_NOTE
ADD COLUMN last_updated_date timestamp AFTER status;
错误日志:
Hibernate: select next_val as id_val from hibernate_sequence for update
Hibernate: update hibernate_sequence set next_val= ? where next_val=?
test
Hibernate: insert into T_NOTE (DESCRIPTION, LAST_UPDATED_DATE, STATUS, TITLE, ID) values (?, ?, ?, ?, ?)
Hibernate: update T_TAG set TAG_NAME=? where TAG_ID=?
2020-04-11 18:02:40.647 ERROR 3614 --- [nio-8080-exec-1] o.h.i.ExceptionMapperStandardImpl : HHH000346: Error during managed flush [Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.sandeep.SpringBootDemo.model.Tag#0]]
org.springframework.orm.jpa.JpaOptimisticLockingFailureException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.sandeep.SpringBootDemo.model.Tag#0]; nested exception is javax.persistence.OptimisticLockException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.sandeep.SpringBootDemo.model.Tag#0]
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:396)
at org.springframework.orm.jpa.DefaultJpaDialect.translateExceptionIfPossible(DefaultJpaDialect.java:127)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:545)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:746)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:714)
at org.springframework.transaction.interceptor.TransactionAspectSupport.
异常提示我 Tag 被错误地更新,这引发了一个问题,为什么它首先调用 update forTag
而 insert 被正确调用Note
?在发布此问题之前,我尝试寻找解决方案,但找不到任何解决方案。提前致谢!
解决方案
Hibernate 在父插入时为子级调用更新,因为您使用了单向@OneToMany
而不是@ManyToOne
或双向。无论您做什么,Hibernate 都将其建模为 OneToMany。因此,Hibernate 插入您的父项和子项,然后对子项调用 update 以将父外键添加到子表。现在关于为什么你得到异常,正如我所说,Hibernate 在你的关系的许多方面调用更新,但是由于默认行为是可空的设置为 true,它会导致你的错误。请记住,您正在进行单向映射,因此只有关系的一侧知道它。请避免使用 OneToMany 的单向关系。您可以在 Vlad MihalCea 网站上找到许多关于此问题的精彩文章。他是冬眠大师。将 nullable 设置为 false ,它应该可以解决您的问题。
推荐阅读
- swift - 为什么将对象的 y 位置设置为 UIScreen 的高度除以 2 而不是将其置于屏幕顶部?
- c++ - 为什么 valgrind 使用 GLUT 和 PORTAUDIO 报告我的内存肯定丢失了 12 或 24 个字节
- html - div中间的滚动条
- android-r8 - 启用 R8 需要明确的规则来保留所有应用程序包
- java - Commons-lang StringUtils isNotBlank 方法仍然会引发 NPE
- c# - How to create a Windows service that monitors the version of a specific application and modifies a file if it changes
- ffmpeg - sws_scale() 不会简单地将图像从源复制到目标
- c# - Why are independent process taking longer as time goes on?
- javascript - 在打字稿中映射对象类型
- node.js - 错误:关系“my_table”不存在,但实际上存在