Chr*_*ris 6 java hibernate jpa
我们试图在短时间内拯救许多孩子,并且休眠状态不断给出 OptimisticLockException。这是该案例的一个简单示例:
University
id
name
audit_version
Student
id
name
university_id
audit_version
Run Code Online (Sandbox Code Playgroud)
其中 university_id 可以为 null。
java对象看起来像:
@Entity
@Table(name = "university")
@DynamicUpdate
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public class University {
@Id
@SequenceGenerator(name = "university_id_sequence_generator", sequenceName = "university_id_sequence", allocationSize = 1)
@GeneratedValue(strategy = SEQUENCE, generator = "university_id_sequence_generator")
@EqualsAndHashCode.Exclude
private Long id;
@Column(name = "name")
private String name;
@Version
@Column(name = "audit_version")
@EqualsAndHashCode.Exclude
private Long auditVersion;
@OptimisticLock(excluded = true)
@OneToMany(mappedBy = "student")
@ToString.Exclude
private List<Student> student;
}
@Entity
@Table(name = "student")
@DynamicUpdate
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public class Student {
@Id
@SequenceGenerator(name = "student_id_sequence_generator", sequenceName = "student_id_sequence", allocationSize = 1)
@GeneratedValue(strategy = SEQUENCE, generator = "student_id_sequence_generator")
@EqualsAndHashCode.Exclude
private Long id;
@Column(name = "name")
private String name;
@Version
@Column(name = "audit_version")
@EqualsAndHashCode.Exclude
private Long auditVersion;
@OptimisticLock(excluded = true)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "university_id")
@ToString.Exclude
private University university;
}
Run Code Online (Sandbox Code Playgroud)
好像我们分配大学然后保存Student时,如果我们在短时间内做4个以上,我们就会得到OptimisticLockException。即使大学在数据库级别没有改变,休眠似乎也在大学表上创建更新版本。
更新:保存学生的代码
Optional<University> universityInDB = universidyRepository.findById(universtityId);
universityInDB.ifPresent(university -> student.setUniversity(university);
Optional<Student> optionalExistingStudent = studentRepository.findById(student);
if (optionalExistingStudent.isPresent()) {
Student existingStudent = optionalExistingStudent.get();
if (!student.equals(existingStudent)) {
copyContentProperties(student, existingStudent);
studentToReturn = studentRepository.save(existingStudent);
} else {
studentToReturn = existingStudent;
}
} else {
studentToReturn = studentRepository.save(student);
}
private static final String[] IGNORE_PROPERTIES = {"id", "createdOn", "updatedOn", "auditVersion"};
public void copyContentProperties(Object source, Object target) {
BeanUtils.copyProperties(source, target, Arrays.asList(IGNORE_PROPERTIES)));
}
Run Code Online (Sandbox Code Playgroud)
我们尝试了以下
@OptimisticLock(excluded = true)
不起作用,仍然给出乐观锁异常。
@JoinColumn(name = "university_id", updatable=false)
只处理更新,因为我们不保存更新
@JoinColumn(name = "university_id", insertable=false)
工作但不保存关系并且 university_id 始终为空
更改级联行为。唯一一个似乎有意义的值是Cascade.DETACH,但给出一个 org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientPropertyValueException: object 引用未保存的瞬态实例 - 在刷新之前保存瞬态实例。
我们想到的其他解决方案但不确定选择什么
在 409 之后,客户端必须重试他的帖子。对于通过队列发送的对象,队列稍后将重试该条目。我们不希望我们的客户管理这个错误
它不干净,因为当条目来自队列时,我们已经在做,但可能是迄今为止最好的解决方案。
如果没有大量关系,这可能没问题,但是我们有可能在 100 中甚至在 1000 中的情况,这将使对象变得很大,以便在队列中或通过 Rest 调用发送。
我们的整个数据库目前处于 optimisticLocking 中,到目前为止我们设法防止了这些乐观锁定的情况,我们不想仅仅因为这种情况而改变我们的整个锁定策略。也许对模型的那个子集强制悲观锁定,但我还没有看是否可以完成。
除非您需要它,否则它不需要它。 做这个:
University universityProxy = universidyRepository.getOne(universityId);
student.setUniversity(universityProxy);
Run Code Online (Sandbox Code Playgroud)
为了分配 a,University您不必将University实体加载到上下文中。因为从技术上讲,您只需要使用适当的外键()保存学生记录university_id。因此,当您拥有一个时university_id,您可以使用存储库方法创建一个 Hibernate 代理getOne()。
@OneToMany映射 @OneToMany(mappedBy = "student") // should be (mappedBy = "university")
@ToString.Exclude
private List<Student> student;
Run Code Online (Sandbox Code Playgroud)
add()or remove(), or 这样的方法clear() private List<Student> student; // should be ... = new ArrayList<>();
Run Code Online (Sandbox Code Playgroud)
*总体来说有些地方不太清楚,比如studentRepository.findById(student);。因此,如果你想得到正确的答案,最好把你的问题说清楚。
| 归档时间: |
|
| 查看次数: |
523 次 |
| 最近记录: |