TL; DR
Для OneToMany
сопоставления между Note
и Tag
с использованием третьей таблицы Note_tag
, save()
не может сохранить Note
сущность.
Справочная информация:
Итак, я работал над этим NoteApp ( Место репозитория Github ), которое сохраняет примечание с заголовком, описанием, статусом и тегом (тег является строковым значением). В качестве обновления функции я подумал добавить несколько тегов для заметки. Для этого я создал таблицу тегов и третью таблицу ассоциаций тега и заметки с использованием аннотации faily straigt forward @JoinTable
. Эта функция привела меня к вышеупомянутой проблеме при сохранении сущности Note.
Что я использую за экраном:
Java 1.8, Hiberanate, SpringBoot
Подробнее о техническом стеке на здесь
То, что у меня уже работает:
Save()
Note
без Tag
с.
My 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**/
}
My Tag. 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;
}
My 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;
}
My 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
, тогда как вставка корректно вызывается для Note
? Я пытался найти решения, прежде чем опубликовать этот вопрос, но не смог найти ни одного. Заранее спасибо!