![](/img/trans.png)
[英]PersistentObjectException: detached entity passed to persist
[英]JPA PersistentObjectException: detached entity passed to persist
我在嘗試使用Spring Data JPA和Hibernate作為JPA提供程序進行批處理插入操作時遇到問題。
我的服務有以下方法。 這是引發異常的地方。
@Transactional
private void saveAppointments() {
// create StageFile reference object
StageFile file = new StageFile();
file.setFileName("3312_APPOINTMENT.API");
file.setDeleteFlag('N');
file.setInstitution(institution);
for (StageAppointment appointment : appointments) {
appointment.setStageFile(file);
stageAppointmentRepository.save(appointment);
}
}
@Transactional
private void saveDepartments() {
// create StageFile reference object
StageFile file = new StageFile();
file.setFileName("3312_DEPARTMENT.API");
file.setDeleteFlag('N');
file.setInstitution(institution);
for (StageDepartment department : departments) {
department.setStageFile(file);
stageDepartmentRepository.save(department);
}
}
該機構是一個實例變量,需要提前獲取。
Institution institution = institutionRepository.findByActCode(3312);
我也將實體設置為級聯PERSIST和MERGE。
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "stgAppointmentSeq")
@SequenceGenerator(name = "stgAppointmentSeq", sequenceName = "T_STG_APPOINTMENT_SEQ", allocationSize = 50)
@Column(name = "ID")
private Long id;
@ManyToOne(cascade = {CascadeType.PERSIST,CascadeType.MERGE}, fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "FILE_ID", referencedColumnName = "ID")
private StageFile stageFile;
@ManyToOne(cascade = {CascadeType.PERSIST,CascadeType.MERGE}, fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "STATUS_ID", referencedColumnName = "ID")
private StageStatus stageStatus;
我究竟做錯了什么?
另外,我確定該問題的答案是“是”,但是當我保留具有必需外鍵引用的實體時,是否必須保存完整的關聯對象或僅保存ID? 似乎與JPA的目的背道而馳。
更新:
根據注釋,我更新了代碼以執行單個事務中的所有操作,但沒有區別。
@Transactional
private void saveAppointments() {
Institution institution = institutionRepository.findByActCode(3312);
StageStatus stageStatus = stageStatusRepository.findOne(1L);
// create StageFile reference object
StageFile file = new StageFile();
file.setFileName("3312_APPOINTMENT.API");
file.setDeleteFlag('N');
file.setInstitution(institution);
for (StageAppointment appointment : appointments) {
appointment.setStageFile(file);
appointment.setStageStatus(stageStatus);
stageAppointmentRepository.save(appointment);
}
}
更新2:
為什么此代碼有效
@Transactional
private void saveUsingTransaction() {
Institution institution = institutionRepository.findByActCode(3312);
StageStatus status = stageStatusRepository.findOne(1L);
StageFile file = new StageFile();
file.setDeleteFlag('N');
file.setFileName("3312_DIRECTORY.API");
file.setInstitution(institution);
StageDirectory directory = new StageDirectory();
directory.setLocalId("11111111111111111");
directory.setFirstName("Joe");
directory.setLastName("Joe");
directory.setPrimaryEmail("joe@gmail.com");
directory.setStageFile(file);
directory.setStageStatus(status);
stageDirectoryRepository.save(directory);
}
而且此代碼不
@Transactional
private void savePassingDirectory(StageDirectory directory) {
Institution institution = institutionRepository.findByActCode(3312);
StageStatus stageStatus = stageStatusRepository.findOne(1L);
// create StageFile reference object
StageFile file = new StageFile();
file.setFileName("3312_DIRECTORY.API");
file.setInstitution(institution);
file.setDeleteFlag('N');
directory.setStageFile(file);
directory.setStageStatus(stageStatus);
stageDirectoryRepository.save(directory);
}
@Transactional
僅適用於從外部對象到托管Bean的方法調用。
容器不會攔截類內方法調用(按照定義,私有方法只能以這種方式調用),因此對於這些方法,@ @Transactional
注釋無效。 因此,我認為您需要檢查交易邊界的實際位置。
我的猜測是saveAppointments
當前在任何事務之外運行。 你institutionRepository.findByActCode()
是可能托管bean正確調用,這樣使用事務。 當該方法再次返回時,在調用stageAppointmentRepository.save()
時,您將在任何事務之外進行操作以最終進入新事務。
首先,您必須確保方法saveAppointments
本身實際上在事務中運行(例如,將其public
並從@Inject
直接調用它),然后必須確保后續方法調用重復使用同一事務,而不是啟動新的(即沒有@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
)
有趣的是,每當有人使用實體管理器一段時間后,此問題就會彈出...
因此,您已將數據庫連接到持久層,現在您想知道,如果您的實體離開生態系統,為什么會崩潰。
這樣做的原因僅是因為一旦實體離開其邊界(即事務上下文),它就會與實體管理器分離。 如果要存儲其更改,則必須再次附加。
您可以在以下位置閱讀如何完成此操作: 在Hibernate中重新附加分離對象的正確方法是什么?
在您的情況下, appointments
分離了。 因此,您必須檢入.save(...)
方法,如果傳遞的對象是否在當前實體管理器的上下文中,否則,請重新附加它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.